This notebook contains all multivariate analyses of zoobenthic community structure using the new, nearly unheard-of modeling methods: packages mvabund, boral.
Again, to make it self-contained, there will be the same repetitive setup/data import/preparation part.


Setup!

Define the working subdirectories.

## print the working directory, just to be on the safe side
paste("You are here: ", getwd())

data.dir <- "data"    ## input data files
functions.dir <- "R"  ## functions & scripts
save.dir <- "output"  ## clean data, output from models & more complex calculations
figures.dir <- "figs" ## plots & figures 

Import libraries.

library(here) ## painless relative paths to subdurectories, etc.
library(tidyverse) ## data manipulation, cleaning, aggregation
library(viridis) ## smart & pretty colour schemes
library(mvabund) ## multivariate modeling analyses in ecology
library(boral) ## more multivariate modeling analyses in ecology

Organize some commonly-used ggplot2 modifications into a more convenient (and less repetitive) format. One day, I MUST figure out the proper way to set the theme..

## ggplot settings & things that I keep reusing
# ggplot_theme <- list(
#   theme_bw(),
#   theme(element_text(family = "Times"))
# )
## always use black-and-white theme
theme_set(theme_bw())
## helper to adjust ggplot text size & avoid repetitions 
text_size <- function(text.x = NULL,
                      text.y = NULL,
                      title.x = NULL,
                      title.y = NULL,
                      legend.text = NULL,
                      legend.title = NULL, 
                      strip.x = NULL, 
                      strip.y = NULL) {
  theme(axis.text.x = element_text(size = text.x),
        axis.text.y = element_text(size = text.y),
        axis.title.x = element_text(size = title.x),
        axis.title.y = element_text(size = title.y),
        legend.text = element_text(size = legend.text), 
        legend.title = element_text(size = legend.title), 
        strip.text.x = element_text(size = strip.x), 
        strip.text.y = element_text(size = strip.y)
        )
}
## log y/min + 1 transform - useful for species counts/biomass data visualization
log_y_min <- function(y) {
  log(y / min(y[y > 0]) + 1)
}

Sand stations (Burgas Bay, 2013-2014)

Import zoobenthic abundance data (cleaned and prepared).

zoo.abnd.sand <- read_csv(here(save.dir, "abnd_sand_orig_clean.csv"))

## convert station to factor (better safe than sorry later, when the stations are not plotted in the order I want them)
(zoo.abnd.sand <- zoo.abnd.sand %>% 
    mutate(station = factor(station, levels = c("Kraimorie", "Chukalya", "Akin", "Sozopol", "Agalina", "Paraskeva")))
)

Remove the all-0 species (= not present in the current dataset).
Maybe also remove the singletons (species appearing only once in the whole dataset and represented by a single individual = so rare that it’s unlikely they carry important information, but it would probably improve the run times).

(zoo.abnd.flt.sand <- zoo.abnd.sand %>%
   select(-c(station:replicate)) %>%
   select(which(colSums(.) > 0))
)
LVM - model-based ordination

Perform a model-based unconstrained ordination by fiting a pure latent variable model (package boral - Hui et al., 2014). This will allow to visualize the multivariate stations x species data - similar to nMDS, can be interpreted in the same way.
I’m including a (fixed) row effect to account for differences in site total abundance - this way, the ordination is in terms of species composition.
NB this takes about a million years to run!

lvm.sand <- boral(y = zoo.abnd.flt.sand, 
                  family = "negative.binomial",
                  
                  ## we want to control for site effects - there are 6 sites with 9 replicates each
                  row.eff = "fixed", row.ids = matrix(rep(1:6, each = 9), ncol = 1),  
                  ## 2 latent variables = 2 axes on which to represent the zoobenthic data
                  lv.control = list(num.lv = 2) 
                  
     #              ## example control structure, to check if function does what I want, because otherwise it takes an intolerably long time, and I'll shoot myself if I have to wait for it again
     #              mcmc.control = list(n.burnin = 10, n.iteration = 100,
     # n.thin = 1)
     #              
     
                  )

Check the summary and diagnostic plots for the LVM.

plot(lvm.sand)
NULL

The residuals plots look fine (no patterns in the residuals vs fitted, so variance is homogeneous, the quantile plot shows a normal distribution of the residuals) - the model fits the data pretty well.

Save the sand LVM.

write_rds(lvm.sand, 
          here(save.dir, "lvm_sand.RDS"))

Examine the biplot obtained by fitting the LVM, as well as the 20 most “important” species.

lvsplot(lvm.sand, jitter = T, biplot = TRUE, ind.spp = 20)
Only the first 20 ``most important'' latent variable coefficients included in biplot

All in all, the final result resembles the nMDS ordination very much - same 4 clusters (Kraimorie + Chukalya, AKin, Agalina, Sozopol + Paraskeva). Kraimorie and Chukalya are better distinguished on the LVM plot than on the MDS, but still.
The run time is extremely, extremely long (~1h), but the data don’t need to be transformed, and the model fit can be examined and adjusted if necessary.
The species singled out as significant are probably somewhat different - have to check!

Redo the biplot, because this one is not very pretty. I’m not adding the species on top, first because I’m too lazy to figure out the procedure for ordering them, and second because the plot gets too busy.

Make the plot and save it.

## save the LVM plot for the sand stations
ggsave(file = here(figures.dir, "lvm_sand.png"), 
       plot.lvm.sand, 
       width = 15, units = "cm", dpi = 300)
GLM fitting for abundance - environmental data

Let’s fit GLMs to the sites x species matrix to try and explain the observed differences in community structure by the variation of the environmental parameters.
These functions all come from package mvabund.
Import the environmental data - the one cleaned, prepared and saved in the previous notebook (classical multivariate methods). It contains long-term averages for the water column data (2009-2011 + 2013-2014) at each station, repeated for each replicate, and the sediment data (2013-2014), again repeated to the same number of replicates. Only the variables determined to be significant by PCA are kept.

env.sand <- read_csv(here(save.dir, "env_data_ordinations_sand.csv"))

## convert station to factor
(env.sand <- env.sand %>% 
    mutate(station = factor(station,
                            levels = c("Kraimorie", "Chukalya", "Akin", "Sozopol", "Agalina", "Paraskeva")))
)

Station is a factor, the rest of the variables are numeric.

Turn the zoobenthic data (minus the all-0 taxa) into a matrix - easier for the mvabund package and methods to deal with.

## there is already one subset of filtered count data (54 x 147) - use it 
zoo.mvabnd.sand <- mvabund(zoo.abnd.flt.sand)
manyGLM by LVM clusters

First, let’s see if the groups from the latent variable model (more or less equal to the clusters from the classical ordination) are valid, and which species exhibit a response.

## construct the vector of the clusters by hand, it's easier that way.. 
lvm.clusters.sand <- c(rep(1, times = 18), rep(2:4, each = 9), rep(3, times = 9))

## convert to factor
(lvm.clusters.sand <- factor(lvm.clusters.sand))

Check the model assumptions. 1. Mean-variance assumption => determines the choice of family parameter. Can be checked by plotting residuals vs fits: if little pattern - the chosen mean-variance assumption is plausible.
Another way: direct plotting (variance ~ mean), for each species within each factor level.

plot(manyglm(zoo.mvabnd.sand ~ lvm.clusters.sand, family = "negative.binomial"))

meanvar.plot(zoo.mvabnd.sand ~ lvm.clusters.sand, table = TRUE)
START SECTION 2 
Plotting if overlay is TRUE
using grouping variable lvm.clusters.sand 290 mean values were 0 and could 
                                        not be included in the log-plot
using grouping variable lvm.clusters.sand 290 variance values were 0 and could not 
                                        be included in the log-plot
FINISHED SECTION 2 
$mean
  Chamelea.gallina Protodorvillea.kefersteini Oligochaeta Microdeutopus.versiculatus
1        5.0555556                 22.7222222  29.2222222                  0.1666667
2       10.1111111                190.5555556 187.0000000                  0.0000000
3      140.3888889                  0.8333333   0.2222222                  0.0000000
4        0.3333333                 60.2222222  20.2222222                136.5555556
  Heteromastus.filiformis Melinna.palmata Prionospio.cirrifera Lentidium.mediterraneum
1             62.72222222     51.55555556           26.0000000                 0.00000
2              0.00000000      0.00000000            3.0000000                 0.00000
3              0.05555556      0.05555556            0.3333333                21.77778
4              0.22222222      0.00000000            0.0000000                 0.00000
  Eurydice.dollfusi Polygordius.neapolitanus Branchiostoma.lanceolatum Ampelisca.diadema
1         0.0000000                 1.333333                 0.0000000          9.944444
2         6.5555556                 8.444444                23.1111111          6.666667
3         0.7777778                 0.000000                 0.5555556          2.111111
4        34.7777778                22.888889                 9.5555556          1.333333
  Melita.palmata Bittium.reticulatum Capitella.minima Nemertea Micronephthys.stammeri
1        0.00000           9.7222222        6.4444444 2.222222               3.944444
2        0.00000           3.8888889        0.1111111 3.555556               0.000000
3        0.00000           1.0555556        2.6666667 2.055556               3.277778
4       31.77778           0.8888889        2.1111111 6.666667               3.222222
  Pseudocuma.longicorne Polycirrus.caliendrum Sphaerosyllis.hystrix
1             0.0000000               0.00000             1.0000000
2             3.3333333               0.00000             2.7777778
3             7.0000000               0.00000             0.2222222
4             0.1111111              17.22222            11.1111111
  Monocorophium.acherusicum Polycirrus.jubatus Ophelia.limacina Spio.filicornis
1                 4.9444444            0.00000        0.0000000      0.05555556
2                 0.7777778            0.00000       12.3333333      0.00000000
3                 0.1111111            0.00000        0.1111111      7.11111111
4                 5.3333333           14.88889        2.2222222      0.00000000
   Hirudinea Lindrilus.flavocapitatus Polydora.ciliata Streptosyllis.bidentata
1 0.05555556                0.2222222        6.7222222                 0.00000
2 4.11111111               13.6666667        0.0000000                 0.00000
3 0.00000000                0.0000000        0.1111111                 0.00000
4 9.88888889                0.0000000        0.0000000                13.66667
        Acari Anadara.kagoshimensis Abra.alba Parvicardium.exiguum Exogone.naidina
1  0.05555556              5.666667 3.0000000            4.0000000       1.2777778
2  0.33333333              0.000000 0.4444444            0.3333333       0.6666667
3  0.00000000              0.000000 2.3888889            0.9444444       1.2222222
4 11.88888889              0.000000 0.0000000            0.5555556       4.5555556
  Nototropis.guttatus Microphthalmus.fragilis Lagis.koreni Nephtys.cirrosa
1           0.4444444                0.000000    4.2222222       1.0000000
2           4.7777778                6.333333    0.1111111       0.0000000
3           0.6111111                0.000000    0.0000000       3.1111111
4           2.3333333                2.777778    0.2222222       0.2222222
  Lucinella.divaricata Perioculodes.longimanus Bathyporeia.guilliamsoniana
1             0.000000               2.1666667                   0.0000000
2             0.000000               1.3333333                   4.7777778
3             3.666667               0.5555556                   1.1111111
4             0.000000               0.5555556                   0.1111111
  Glycera.tridactyla Tellina.tenuis Aonides.paucibranchiata Caecum.armoricum
1          2.7222222      0.5000000               2.8333333        0.0000000
2          0.0000000      0.5555556               0.0000000        0.2222222
3          0.7777778      2.3333333               0.0000000        0.0000000
4          0.1111111      0.0000000               0.4444444        5.7777778
  Bodotria.arenosa Spisula.subtruncata Harmothoe.reticulata Eunice.vittata Turbellaria
1        0.3333333          0.05555556             1.888889      0.1666667   1.1111111
2        1.4444444          0.00000000             0.000000      0.0000000   0.4444444
3        0.0000000          2.72222222             0.000000      0.0000000   0.3888889
4        3.5555556          0.00000000             1.555556      4.4444444   1.0000000
  Diogenes.pugilator Loripes.orbiculatus Mytilaster.lineatus Genetyllis.tuberculata
1          0.9444444          0.05555556           1.0555556              0.1111111
2          0.7777778          0.00000000           1.0000000              0.0000000
3          0.5555556          2.00000000           0.3333333              0.5000000
4          0.4444444          0.00000000           0.3333333              2.7777778
  Iphinoe.tenella Dinophilus.gyrociliatus Perinereis.cultrifera Pitar.rudis
1        1.888889              0.27777778            0.05555556   1.2222222
2        0.000000              0.00000000            0.33333333   0.0000000
3        0.000000              0.05555556            0.27777778   0.0000000
4        0.000000              3.00000000            2.33333333   0.7777778
  Syllis.hyalina Leiochone.leiopygos Salvatoria.clavata Amphibalanus.improvisus
1       0.000000           1.4444444          0.0000000               0.9444444
2       0.000000           0.0000000          0.5555556               0.4444444
3       0.000000           0.0000000          0.0000000               0.2222222
4       3.222222           0.2222222          2.5555556               0.2222222
  Capitella.capitata Syllis.gracilis Decapoda.larvae Magelona.papillicornis
1          0.7777778       0.3888889       1.2777778              0.0000000
2          0.2222222       0.0000000       0.1111111              0.1111111
3          0.3888889       0.0000000       0.0000000              1.2222222
4          0.4444444       2.1111111       0.1111111              0.0000000
  Tritia.neritea Alitta.succinea Eteone.sp. Schistomeringos.rudolphi Microphthalmus.sp.
1       0.000000      0.50000000  0.2222222               0.00000000          0.0000000
2       0.000000      0.11111111  0.0000000               0.00000000          0.0000000
3       1.222222      0.05555556  0.2222222               0.05555556          0.3888889
4       0.000000      1.11111111  1.4444444               1.88888889          1.0000000
  Caecum.trachea Donax.venustus Mysta.picta Glycera.sp. Odostomia.plicata
1      0.0000000      0.0000000   0.1111111   0.6111111         0.1111111
2      0.5555556      0.0000000   0.2222222   0.0000000         0.0000000
3      0.0000000      0.8333333   0.4444444   0.0000000         0.6111111
4      1.1111111      0.0000000   0.3333333   0.3333333         0.0000000
  Apseudopsis.ostroumovi Cytharella.costulata Kellia.suborbicularis
1             0.38888889           0.61111111             0.6666667
2             0.00000000           0.00000000             0.0000000
3             0.05555556           0.05555556             0.0000000
4             0.44444444           0.00000000             0.0000000
  Leptosynapta.inhaerens Spionidae Tritia.reticulata Gastrosaccus.sanctus
1               0.000000 0.3888889         0.3888889           0.05555556
2               0.000000 0.1111111         0.5555556           0.66666667
3               0.000000 0.0000000         0.0000000           0.22222222
4               1.333333 0.4444444         0.0000000           0.00000000
  Micromaldane.ornithochaeta  Phoronida Holothuroidea Nereis.perivisceralis
1                  0.0000000 0.55555556      0.000000                     0
2                  0.0000000 0.00000000      0.000000                     0
3                  0.6111111 0.05555556      0.000000                     0
4                  0.0000000 0.00000000      1.111111                     1
  Phyllodoce.sp. Amphitritides.gracilis Gammaridae Amphipoda Harmothoe.imbricata
1     0.11111111              0.0000000 0.00000000 0.0000000           0.3888889
2     0.22222222              0.0000000 0.77777778 0.7777778           0.0000000
3     0.05555556              0.0000000 0.05555556 0.0000000           0.0000000
4     0.44444444              0.8888889 0.00000000 0.0000000           0.0000000
  Mytilus.galloprovincialis Pholoe.inornata Pisione.remota Ampithoe.sp.
1                0.05555556       0.0000000     0.05555556    0.0000000
2                0.00000000       0.0000000     0.44444444    0.3333333
3                0.00000000       0.0000000     0.00000000    0.1666667
4                0.66666667       0.7777778     0.22222222    0.0000000
  Paradoneis.harpagonea Platyhelminthes Platynereis.dumerilii Rissoa.membranacea
1             0.0000000       0.0000000             0.0000000          0.0000000
2             0.0000000       0.2222222             0.0000000          0.0000000
3             0.3333333       0.0000000             0.0000000          0.3333333
4             0.0000000       0.4444444             0.6666667          0.0000000
  Brachynotus.sexdentatus Eulalia.viridis Microdeutopus.gryllotalpa Nereis.pelagica
1               0.2777778      0.05555556                 0.1111111       0.0000000
2               0.0000000      0.00000000                 0.1111111       0.0000000
3               0.0000000      0.00000000                 0.1111111       0.0000000
4               0.0000000      0.44444444                 0.0000000       0.5555556
  Rapana.venosa Sabellaria.taurica Steromphala.divaricata Aricidea.claudiae
1     0.2777778          0.2777778              0.0000000         0.2222222
2     0.0000000          0.0000000              0.0000000         0.0000000
3     0.0000000          0.0000000              0.0000000         0.0000000
4     0.0000000          0.0000000              0.5555556         0.0000000
  Monocorophium.insidiosum Nereis.pulsatoria Parthenina.interstincta Protodrilus.sp.
1                0.0000000        0.16666667              0.05555556       0.0000000
2                0.0000000        0.00000000              0.00000000       0.4444444
3                0.2222222        0.05555556              0.16666667       0.0000000
4                0.0000000        0.00000000              0.00000000       0.0000000
  Sternaspis.scutata Tellina.fabula Cerastoderma.edule Chondrochelia.savignyi
1          0.0000000      0.0000000          0.0000000              0.0000000
2          0.4444444      0.0000000          0.0000000              0.0000000
3          0.0000000      0.2222222          0.1666667              0.0000000
4          0.0000000      0.0000000          0.0000000              0.3333333
  Crassicorophium.crassicorne Magelona.rosea Polititapes.aureus Polychaeta.larvae
1                   0.0000000      0.0000000          0.1666667         0.0000000
2                   0.3333333      0.0000000          0.0000000         0.3333333
3                   0.0000000      0.1666667          0.0000000         0.0000000
4                   0.0000000      0.0000000          0.0000000         0.0000000
  Retusa.variabilis Brachystomia.scalaris Eteone.flava Hydrobia.sp. Mactra.stultorum
1         0.0000000             0.0000000    0.0000000   0.00000000        0.0000000
2         0.0000000             0.0000000    0.0000000   0.00000000        0.0000000
3         0.1666667             0.1111111    0.1111111   0.05555556        0.1111111
4         0.0000000             0.0000000    0.0000000   0.11111111        0.0000000
  Nephtyidae Papillicardium.papillosum   Abra.sp. Acanthocardia.tuberculata Actiniaria
1  0.0000000                 0.0000000 0.00000000                0.00000000 0.00000000
2  0.0000000                 0.0000000 0.00000000                0.00000000 0.00000000
3  0.1111111                 0.1111111 0.05555556                0.05555556 0.05555556
4  0.0000000                 0.0000000 0.00000000                0.00000000 0.00000000
   Cardiidae Cerastoderma.glaucum Cumopsis.goodsir Elaphognathia.bacescoi
1 0.00000000           0.05555556       0.00000000              0.0000000
2 0.00000000           0.00000000       0.00000000              0.0000000
3 0.05555556           0.00000000       0.05555556              0.0000000
4 0.00000000           0.00000000       0.00000000              0.1111111
  Eurydice.pontica Hydrobia.acuta Iphinoe.sp. Lysidice.ninetta Maldanidae
1        0.0000000     0.05555556   0.0000000        0.0000000 0.00000000
2        0.1111111     0.00000000   0.1111111        0.1111111 0.00000000
3        0.0000000     0.00000000   0.0000000        0.0000000 0.05555556
4        0.0000000     0.00000000   0.0000000        0.0000000 0.00000000
  Microdeutopus.sp. Neanthes.sp. Nereididae Pestarella.candida Pisces.larvae
1        0.00000000   0.05555556  0.0000000          0.0000000    0.05555556
2        0.00000000   0.00000000  0.1111111          0.0000000    0.00000000
3        0.05555556   0.00000000  0.0000000          0.0000000    0.00000000
4        0.00000000   0.00000000  0.0000000          0.1111111    0.00000000
  Retusa.truncatula Rhithropanopeus.harrisii Stenothoe.monoculoides Upogebia.pusilla
1        0.00000000                0.0000000              0.0000000        0.0000000
2        0.00000000                0.0000000              0.0000000        0.0000000
3        0.05555556                0.0000000              0.0000000        0.0000000
4        0.00000000                0.1111111              0.1111111        0.1111111

$var
  Chamelea.gallina Protodorvillea.kefersteini  Oligochaeta Microdeutopus.versiculatus
1         32.05556                707.0359477 3.339477e+02                      0.500
2         38.86111               7209.2777778 3.244850e+04                      0.000
3       7120.36928                  0.9705882 3.006536e-01                      0.000
4          0.25000               2202.9444444 1.089444e+02                   8235.778
  Heteromastus.filiformis Melinna.palmata Prionospio.cirrifera Lentidium.mediterraneum
1            1.564683e+03    2.225908e+03          339.2941176                   0.000
2            0.000000e+00    0.000000e+00           17.7500000                   0.000
3            5.555556e-02    5.555556e-02            0.4705882                2097.242
4            4.444444e-01    0.000000e+00            0.0000000                   0.000
  Eurydice.dollfusi Polygordius.neapolitanus Branchiostoma.lanceolatum Ampelisca.diadema
1          0.000000                 10.23529                 0.0000000         107.93791
2         46.277778                 50.02778                52.8611111          59.50000
3          3.712418                  0.00000                 0.7320261           7.51634
4        638.944444                 68.11111                12.0277778           1.50000
  Melita.palmata Bittium.reticulatum Capitella.minima  Nemertea Micronephthys.stammeri
1         0.0000          142.447712       48.2614379  4.418301              12.173203
2         0.0000            9.861111        0.1111111 45.777778               0.000000
3         0.0000            1.349673       38.0000000  9.702614               5.388889
4       281.4444            1.611111        5.3611111 62.750000               3.944444
  Pseudocuma.longicorne Polycirrus.caliendrum Sphaerosyllis.hystrix
1             0.0000000                0.0000             2.7058824
2            16.0000000                0.0000             8.9444444
3            38.0000000                0.0000             0.5359477
4             0.1111111              323.6944            72.8611111
  Monocorophium.acherusicum Polycirrus.jubatus Ophelia.limacina Spio.filicornis
1                17.7026144            0.00000        0.0000000      0.05555556
2                 1.4444444            0.00000       42.5000000      0.00000000
3                 0.1045752            0.00000        0.1045752    136.81045752
4                26.0000000           64.11111        6.1944444      0.00000000
    Hirudinea Lindrilus.flavocapitatus Polydora.ciliata Streptosyllis.bidentata
1  0.05555556                0.8888889       64.5653595                    0.00
2  8.11111111              338.2500000        0.0000000                    0.00
3  0.00000000                0.0000000        0.1045752                    0.00
4 36.61111111                0.0000000        0.0000000                   18.75
        Acari Anadara.kagoshimensis Abra.alba Parvicardium.exiguum Exogone.naidina
1  0.05555556              10.23529 10.470588            7.0588235        1.506536
2  0.50000000               0.00000  1.777778            0.2500000        0.750000
3  0.00000000               0.00000  6.604575            1.2320261        1.947712
4 69.61111111               0.00000  0.000000            0.5277778       59.277778
  Nototropis.guttatus Microphthalmus.fragilis Lagis.koreni Nephtys.cirrosa
1           0.3790850                 0.00000    7.3594771       3.2941176
2           8.1944444                33.50000    0.1111111       0.0000000
3           0.8398693                 0.00000    0.0000000       6.4575163
4           5.2500000                13.94444    0.1944444       0.4444444
  Lucinella.divaricata Perioculodes.longimanus Bathyporeia.guilliamsoniana
1              0.00000               2.8529412                   0.0000000
2              0.00000               3.2500000                   6.9444444
3             56.23529               0.7320261                   1.7516340
4              0.00000               1.7777778                   0.1111111
  Glycera.tridactyla Tellina.tenuis Aonides.paucibranchiata Caecum.armoricum
1         14.0947712      0.5000000               18.852941        0.0000000
2          0.0000000      0.5277778                0.000000        0.4444444
3          1.8300654     16.5882353                0.000000        0.0000000
4          0.1111111      0.0000000                1.027778       55.9444444
  Bodotria.arenosa Spisula.subtruncata Harmothoe.reticulata Eunice.vittata Turbellaria
1        0.7058824          0.05555556             2.928105      0.1470588   4.3398693
2        5.2777778          0.00000000             0.000000      0.0000000   0.5277778
3        0.0000000          6.44771242             0.000000      0.0000000   0.7222222
4        4.5277778          0.00000000             1.277778     13.5277778   1.2500000
  Diogenes.pugilator Loripes.orbiculatus Mytilaster.lineatus Genetyllis.tuberculata
1          0.7614379          0.05555556           0.7614379              0.1045752
2          1.1944444          0.00000000           2.0000000              0.0000000
3          0.3790850          9.05882353           0.2352941              0.8529412
4          0.2777778          0.00000000           0.2500000             15.1944444
  Iphinoe.tenella Dinophilus.gyrociliatus Perinereis.cultrifera Pitar.rudis
1         3.51634              0.56535948            0.05555556    8.771242
2         0.00000              0.00000000            1.00000000    0.000000
3         0.00000              0.05555556            0.21241830    0.000000
4         0.00000              5.75000000            7.50000000    1.194444
  Syllis.hyalina Leiochone.leiopygos Salvatoria.clavata Amphibalanus.improvisus
1       0.000000           2.0261438          0.0000000               0.8790850
2       0.000000           0.0000000          0.7777778               0.5277778
3       0.000000           0.0000000          0.0000000               0.1830065
4       8.444444           0.4444444         11.5277778               0.1944444
  Capitella.capitata Syllis.gracilis Decapoda.larvae Magelona.papillicornis
1          1.5947712       0.4869281      14.8006536              0.0000000
2          0.4444444       0.0000000       0.1111111              0.1111111
3          0.3692810       0.0000000       0.0000000              0.8888889
4          0.7777778       2.8611111       0.1111111              0.0000000
  Tritia.neritea Alitta.succinea Eteone.sp. Schistomeringos.rudolphi Microphthalmus.sp.
1       0.000000      0.85294118  0.3006536               0.00000000          0.0000000
2       0.000000      0.11111111  0.0000000               0.00000000          0.0000000
3       3.477124      0.05555556  0.3006536               0.05555556          0.7222222
4       0.000000      1.61111111  3.5277778               2.11111111          4.5000000
  Caecum.trachea Donax.venustus Mysta.picta Glycera.sp. Odostomia.plicata
1       0.000000       0.000000   0.1045752    1.663399         0.2222222
2       1.777778       0.000000   0.1944444    0.000000         0.0000000
3       0.000000       1.088235   0.6143791    0.000000         1.6633987
4       2.861111       0.000000   0.5000000    0.500000         0.0000000
  Apseudopsis.ostroumovi Cytharella.costulata Kellia.suborbicularis
1             0.60457516           0.36928105              1.882353
2             0.00000000           0.00000000              0.000000
3             0.05555556           0.05555556              0.000000
4             1.02777778           0.00000000              0.000000
  Leptosynapta.inhaerens Spionidae Tritia.reticulata Gastrosaccus.sanctus
1                   0.00 2.7222222          0.369281           0.05555556
2                   0.00 0.1111111          1.777778           1.25000000
3                   0.00 0.0000000          0.000000           0.30065359
4                   8.75 1.0277778          0.000000           0.00000000
  Micromaldane.ornithochaeta  Phoronida Holothuroidea Nereis.perivisceralis
1                   0.000000 0.73202614      0.000000                  0.00
2                   0.000000 0.00000000      0.000000                  0.00
3                   1.075163 0.05555556      0.000000                  0.00
4                   0.000000 0.00000000      1.861111                  2.75
  Phyllodoce.sp. Amphitritides.gracilis Gammaridae Amphipoda Harmothoe.imbricata
1     0.10457516               0.000000 0.00000000  0.000000             2.01634
2     0.44444444               0.000000 2.94444444  5.444444             0.00000
3     0.05555556               0.000000 0.05555556  0.000000             0.00000
4     0.77777778               4.111111 0.00000000  0.000000             0.00000
  Mytilus.galloprovincialis Pholoe.inornata Pisione.remota Ampithoe.sp.
1                0.05555556        0.000000     0.05555556    0.0000000
2                0.00000000        0.000000     0.52777778    1.0000000
3                0.00000000        0.000000     0.00000000    0.2647059
4                4.00000000        3.944444     0.19444444    0.0000000
  Paradoneis.harpagonea Platyhelminthes Platynereis.dumerilii Rissoa.membranacea
1             0.0000000       0.0000000                  0.00          0.0000000
2             0.0000000       0.1944444                  0.00          0.0000000
3             0.5882353       0.0000000                  0.00          0.9411765
4             0.0000000       0.2777778                  2.75          0.0000000
  Brachynotus.sexdentatus Eulalia.viridis Microdeutopus.gryllotalpa Nereis.pelagica
1               0.3300654      0.05555556                 0.2222222        0.000000
2               0.0000000      0.00000000                 0.1111111        0.000000
3               0.0000000      0.00000000                 0.1045752        0.000000
4               0.0000000      1.02777778                 0.0000000        2.777778
  Rapana.venosa Sabellaria.taurica Steromphala.divaricata Aricidea.claudiae
1     0.3300654          0.3300654              0.0000000         0.5359477
2     0.0000000          0.0000000              0.0000000         0.0000000
3     0.0000000          0.0000000              0.0000000         0.0000000
4     0.0000000          0.0000000              0.7777778         0.0000000
  Monocorophium.insidiosum Nereis.pulsatoria Parthenina.interstincta Protodrilus.sp.
1                0.0000000        0.26470588              0.05555556        0.000000
2                0.0000000        0.00000000              0.00000000        1.777778
3                0.5359477        0.05555556              0.14705882        0.000000
4                0.0000000        0.00000000              0.00000000        0.000000
  Sternaspis.scutata Tellina.fabula Cerastoderma.edule Chondrochelia.savignyi
1           0.000000      0.0000000          0.0000000                      0
2           1.777778      0.0000000          0.0000000                      0
3           0.000000      0.4183007          0.2647059                      0
4           0.000000      0.0000000          0.0000000                      1
  Crassicorophium.crassicorne Magelona.rosea Polititapes.aureus Polychaeta.larvae
1                           0      0.0000000          0.1470588               0.0
2                           1      0.0000000          0.0000000               0.5
3                           0      0.1470588          0.0000000               0.0
4                           0      0.0000000          0.0000000               0.0
  Retusa.variabilis Brachystomia.scalaris Eteone.flava Hydrobia.sp. Mactra.stultorum
1         0.0000000             0.0000000    0.0000000   0.00000000        0.0000000
2         0.0000000             0.0000000    0.0000000   0.00000000        0.0000000
3         0.1470588             0.2222222    0.1045752   0.05555556        0.1045752
4         0.0000000             0.0000000    0.0000000   0.11111111        0.0000000
  Nephtyidae Papillicardium.papillosum   Abra.sp. Acanthocardia.tuberculata Actiniaria
1  0.0000000                 0.0000000 0.00000000                0.00000000 0.00000000
2  0.0000000                 0.0000000 0.00000000                0.00000000 0.00000000
3  0.2222222                 0.1045752 0.05555556                0.05555556 0.05555556
4  0.0000000                 0.0000000 0.00000000                0.00000000 0.00000000
   Cardiidae Cerastoderma.glaucum Cumopsis.goodsir Elaphognathia.bacescoi
1 0.00000000           0.05555556       0.00000000              0.0000000
2 0.00000000           0.00000000       0.00000000              0.0000000
3 0.05555556           0.00000000       0.05555556              0.0000000
4 0.00000000           0.00000000       0.00000000              0.1111111
  Eurydice.pontica Hydrobia.acuta Iphinoe.sp. Lysidice.ninetta Maldanidae
1        0.0000000     0.05555556   0.0000000        0.0000000 0.00000000
2        0.1111111     0.00000000   0.1111111        0.1111111 0.00000000
3        0.0000000     0.00000000   0.0000000        0.0000000 0.05555556
4        0.0000000     0.00000000   0.0000000        0.0000000 0.00000000
  Microdeutopus.sp. Neanthes.sp. Nereididae Pestarella.candida Pisces.larvae
1        0.00000000   0.05555556  0.0000000          0.0000000    0.05555556
2        0.00000000   0.00000000  0.1111111          0.0000000    0.00000000
3        0.05555556   0.00000000  0.0000000          0.0000000    0.00000000
4        0.00000000   0.00000000  0.0000000          0.1111111    0.00000000
  Retusa.truncatula Rhithropanopeus.harrisii Stenothoe.monoculoides Upogebia.pusilla
1        0.00000000                0.0000000              0.0000000        0.0000000
2        0.00000000                0.0000000              0.0000000        0.0000000
3        0.05555556                0.0000000              0.0000000        0.0000000
4        0.00000000                0.1111111              0.1111111        0.1111111

It’s not perfect, but it’s not too terrible either.

  1. Assumed relationship between mean abundance and environmental variables - link function and formula. When quantitative variables are included in the model (for now, not relevant - will be in the next model) -> if there is a trend in size of residuals at different fitted values (e.g. U-shape,..) = violation of the log-linearity assumption.

Everything looks more or less fine; fit the model.

glms.lvm.sand <- manyglm(zoo.mvabnd.sand ~ lvm.clusters.sand, 
                         family = "negative.binomial")

Explore the fit (residuals, diagnostic plots, etc.).

png(filename = here(figures.dir, "diag_pl_sand1.png"), width = 16, height = 10, units = "cm", res = 300)
plot.manyglm(glms.lvm.sand, which = 2)
dev.off()
null device 
          1 

I really don’t like the rainbow palette, but I would like to include these plots in my thesis results.. Will have to do something about it, just not right now.
Save the model!

write_rds(glms.lvm.sand, 
          here(save.dir, "glms_lvm_sand.RDS"))

Let’s see the model summary (NB takes a LOT of time if there are many resamplings!).

(glms.lvm.sand.summary <- summary(glms.lvm.sand, 
                                  test = "LR", p.uni = "adjusted",
                                  nBoot = 999, ## limit the number of permutations if you just want to check it out
                                  show.time = "all")
)

The factor (here - groups outlined by the LVM) is highly significant according to the models.
This also allows us to see which species exhibit a response to the chosen factor. The LR (likelihood ratio) statistic is used as a measure of the strength of individual taxon contributions to the observed patterns. I’ll save the summary for safekeeping, but I’ll also run an anova - to get an analysis of deviance table on the model fit (also better for extracting the species contributions, or at least I know how to do it).

write_rds(glms.lvm.sand.summary, 
          here(save.dir, "glms_lvm_sand_summary.RDS"))

Run the anova on the model.

(glms.lvm.sand.aov <- anova.manyglm(glms.lvm.sand, 
                                    test = "LR", p.uni = "adjusted", 
                                    nBoot = 999, ## limit the number of permutations for a shorter run time   
                                    show.time = "all") 
)

I probably shouldn’t have printed all this out, but oh well who cares.

Save the ANOVA, too.

write_rds(glms.lvm.sand.aov, 
          here(save.dir, "glms_lvm_sand_anova.RDS"))

NOW let’s get the taxa with the highest contributions to the tested pattern (here - clusters in the LVM, which are really the different soft-bottom habitats).

top_n_sp_glm <- function(glms.aov, tot.dev.expl = 0.75) {
  ## helper retrieving the top n species with the highest contribution to the patterns tested by the GLMs, in decreasing order.
  ## Arguments: glms.aov - results from an ANOVA on the fitted GLMs
  ##            dev.explained - proportion of explained deviance to use as cutoff
  
  ## get the change in deviance due to the tested pattern (= 2nd row from table of univariate test stats), and sort the species in order of decreasing contribution
  uni.sorted <- sort(glms.aov$uni.test[2, ], decreasing = TRUE, index.return = FALSE)

  ## start at 10 species and check how much of the deviance is explained by their contributions. Repeat, increasing by increments of 10 until the desired explained deviance (set at function call) is reached. 
  top.n.sp <- 10
  dev.expl <- sum(uni.sorted[1:top.n.sp])/sum(uni.sorted)
  
  while(dev.expl < tot.dev.expl) {
    top.n.sp <- top.n.sp + 10
    dev.expl <- sum(uni.sorted[1:top.n.sp])/sum(uni.sorted)
  }
  
  ## print the total deviance explained - just for information
  print(paste("Total deviance explained:", round(dev.expl, 3)))
  
  ## return the final top species (and their univariate contributions, just in case) 
  top.sp <- uni.sorted[1:top.n.sp]
  return(top.sp)
}

## get the top contributing species for the initial sand GLMs 
(top.sp.glms.lvm.sand <- top_n_sp_glm(glms.lvm.sand.aov, tot.dev.expl = 0.75)
)

## unfortunately, mvabund likes to rename my species when converting the data to matrix (no spaces in names), and since I'm going to look them up in my initial untransformed count data, I have to change them back..   
names(top.sp.glms.lvm.sand) <- names(top.sp.glms.lvm.sand) %>% 
  str_replace(pattern = "\\.", replacement = " ")

top.sp.glms.lvm.sand

Try to plot these top contributing species - for whatever that’s worth, because 50 species on a plot is a monstrosity.

## get the species and their abundances from the original count data, and transform them to long format
(abnd.top.sp.glms.lvm.sand <- zoo.abnd.sand %>% 
   select(station, names(top.sp.glms.lvm.sand)) %>% 
   gather(key = "species", value = "count", -station) %>% 
   ## turn species into a factor, or you'll be very very sorry later, when they're out of order on the plot. NB need to be in REVERSE order, because ggplot plots from bottom to top, and I want the top-contributing species on top. 
   mutate(species = factor(species, levels = rev(names(top.sp.glms.lvm.sand))))
)

plot_top_n <- function(top.n.sp.data, mapping, labs.legend, lab.y, palette) {
  ## helper for plotting top n species. Was hoping to avoid repeating it from way back when, but no dice. 
  ## Arguments: top.n.sp.data - data frame (long) of top species' counts/biomasses at the different stations
  ##            mapping - mappings of the aesthetics
  ##            labs.legend - labels the use for the legend entries
  ##            lab.y - custom label for y axis
  ##            palette - custom colour palette (for consistency with other plots)
  
  ggplot(top.n.sp.data, mapping) +
    geom_point(alpha = 0.75) + # make points larger & partially transparent
    scale_color_brewer(palette = palette,  labels = labs.legend) + 
    ylab(lab.y) + 
    coord_flip() 
}


(plot.top.sp.glms.lvm.sand <- plot_top_n(abnd.top.sp.glms.lvm.sand,
                                         mapping = aes(x = species, y = log_y_min(count), colour = station),
                                         labs.legend = paste0("S", as.numeric(unique(abnd.top.sp.glms.lvm.sand$station))),
                                         lab.y = "Abundance (log(y/min + 1))",
                                         palette = "Set2"
                                        ) +
    theme(legend.position = "top")

)

Well this is a nightmarish plot.. I’ll probably just put this awfulness in a table and call it a day, or play with lvsplot and the modeled ordination plot, if a plot is what’s needed.

Extract the top-contributing species to each cluster (this same nightmare above, but as a table). This chunk is hopelessly ugly and clumsy (and I’ll have to repeat it for the seagrass, too!), but I’m tired of being stuck on this. I still have many, MANY more things to do, and more time-consuming ones too..

top_sp_glms_table <- function(manyglms.obj.smry, group, p = 0.05) {
  ### extracts the top species in a group for which there is an observed effect in a manyglm test, at the specified probability level.
  ### Returns: tibble with the top species for the specified group/cluster, sorted (descending) by univariate LR value of the species, significant at the given p level. 
  
  ## extract the univariate LR coefficients of the species and their p-values 
  sp_univar <- as_tibble(manyglms.obj.smry$uni.test, rownames = "species")
  sp_p <- as_tibble(manyglms.obj.smry$uni.p, rownames = "species")

  ## combine in the same tibble
  sp_all <- left_join(sp_univar, sp_p, by = "species")  
  
  ## rename the columns
  sp_all <- sp_all %>% 
    rename_at(vars(contains(".x")), list(~str_replace_all(., pattern = ".x", ".LR"))) %>% 
    rename_at(vars(contains(".y")), list(~str_replace_all(., pattern = ".y", ".p")))
  
  ## filter only the group/cluster we want, at the p-level we want
  sp_all_flt <- sp_all %>% 
    select(species, contains(group)) %>% 
    filter_at(vars(contains(".p")), all_vars(. < p)) %>%
    arrange_at(vars(contains(".LR")), list(~desc(.)))

}

top.sp.abnd.glms.lvm.sand <- lapply(names(glms.lvm.sand.summary$aliased), function(x) top_sp_glms_table(glms.lvm.sand.summary, x, p = 0.05)) 

## fix species names (remove dot) 
top.sp.abnd.glms.lvm.sand <- lapply(top.sp.abnd.glms.lvm.sand, function(x) x %>% mutate(species = str_replace(species, pattern = "\\.", replacement = " ")))

## rename columns (= group names) - right now they are something like "lvm.clusters.sand2" etc.
top.sp.abnd.glms.lvm.sand <- lapply(top.sp.abnd.glms.lvm.sand, function(x) x %>% rename_at(vars(contains("lvm.clusters.sand")), list(~str_replace_all(., pattern = "lvm.clusters.sand", "group_"))))

top.sp.abnd.glms.lvm.sand <- lapply(top.sp.abnd.glms.lvm.sand, function(x) x %>% rename_at(vars(contains("Intercept")), list(~str_replace_all(., pattern = "\\(Intercept\\)", "group_1"))))


## pull the abundances from the original count df and add to the summary glm tables 
## make a long df of abundances & add clusters  
zoo.abnd.sand.long <- zoo.abnd.sand %>%
  select(-c(month:replicate)) %>%
  gather(key = "species", value = "count", -station) %>% 
  mutate(group = case_when(station %in% c("Kraimorie", "Chukalya") ~ 1, 
                           station == "Akin" ~ 2, 
                           station %in% c("Sozopol", "Paraskeva") ~ 3, 
                           station == "Agalina" ~ 4))

## sum sp abundances by group; nest by group
zoo.abnd.sand.long.smry <- zoo.abnd.sand.long %>% 
  group_by(species, group) %>% 
  summarise(total_count = sum(count)) %>% 
  group_by(group) %>%
  nest()

## add the counts to the group dfs - wow that's an ugly, ugly hack. Wish I had more time to write this up properly.. 
top.sp.abnd.glms.lvm.sand <- map2(top.sp.abnd.glms.lvm.sand, zoo.abnd.sand.long.smry %>% pull(group), ~left_join(.x, zoo.abnd.sand.long.smry %>% filter(group == .y) %>% unnest(), by = "species"))

## since these are sum counts over all the replicates (that's why the monstrous numbers), average them to be mean counts per group. NB different groups consist of different numbers of replicates, b.c. some groups consist of more than one station
(top.sp.abnd.glms.lvm.sand <- map2(top.sp.abnd.glms.lvm.sand, c(18, 9, 18, 9), function(x, y) x %>% mutate(mean_count = total_count/y))
)

To determine the relative taxon contribution to patterns: LR statistic - a measure of strength of individual taxon contributions. LR expresses how many times more likely the data are under one model than the other. This likelihood ratio, or equivalently its logarithm, can then be used to compute a p-value, or, compared to a critical value, to decide whether to reject the null model in favour of the alternative model.

In this case, the model shows which species exhibit a reaction based on the chosen groups - in other words, which species are more likely to be more/less abundant in each group.
For group 1 (= S1-S2), the species/taxa with significantly higher abundance are: Oligochaeta, H. filiformis, P. kefersteini, M. palmata, P. cirrifera, A. diadema (among others); and the ones with significantly lower abundance - even 0, in some cases - S. bidentata, B.lanceolatum, M. papillicornis, Melita palmata, P. jubatus, and so on.
For group 2 (= S3), the species with higher abundance are: B. lanceolatum, O. limacina, Oligochaeta (this is this strange artifact of 2013), P. kefersteini, L. flavocapitatus. The species with lower abundance are: H. filiformis, A. kagoshimensis, M. stammeri, Melinna palmata, etc. For group 3 (= S4-S6), the species with higher abundance are: C. gallina, L. mediterraneum - with very high dominance over practically all others; also Pseudocuma longicorne, Spio filicornis. The species with lower abundance are: H. filiformis, Oligochaetes (to a certain extent - they are still present, though), A. kagoshimensis, L. koreni, Harmothoe reticulata, Iphinoe tenella, Leiochone leiopygos.
For group 4 (= S5), the species with higher abundance are: Microdeutopus versiculatus, Eurydice dollfusi, Melita palmata, Polygordius neapolitanus, Polycirrus caliendrum, Polycirrus jubatus, Streptosyllis bidentata. The species with lower abundance are: A. kagoshimensis, Melinna palmata, P. cirrifera, P. ciliata, A. alba, I. tenella.
I love how the species with the highest variances (e.g. C. gallina, the most conspicuous example) are consistently pushed back - have lower LR scores. This is very good - C. gallina in particular is dominant in group 3, but is present also in all other groups - its substrate/depth preferences are very wide, so this is not uncommon. It’s not automatically pushed to the top of the list, but its reaction is detected by the manyGLM test. Neat! Contrast to the SIMPER results, where the species with the highest variance are consistently at the top - they contribute the most to the similarity, as per the test definition.

I’m going to save these as separate files (manually), then format them as tables - I know it’s a shame, but I’m too frustrated to figure out how to do it programmatically.
I’ll also put them in a word table in my final text, because I don’t want to deal with a million separate ones (embedded excel tables don’t split over multiple pages).

NB In my text, I’m switching the names/places of group 3 and 4, to be consistent with the SIMPER groups (I’m NOT going to repeat all this just to have the numbers match up). So the file names, table names, etc. remain as above. But in the text, I’ll have the following: group 1 = S1-S2, group 2 = S3, group 3 = S5, group 4 = S4-S6. REMEMBER THIS SO THERE IS NO CONFUSION!

manyGLM by environmental parameters

Now, let’s try to see a different thing - which environmental parameters best describe the species response.
I’m going to use the PCA-filtered environmental data - it’s still going to be a slog, with 7 potential predictors..
First, construct the formula for the model - will do it separately in case I need to update it later, etc. This is the full formula with all explanatory variables.

(formula.env.glms.sand <- formula(paste("zoo.mvabnd.sand ~", 
                                        paste(env.sand %>% select(-station) %>% names(), collapse = "+")))
)

Fit the GLMs to the sand abundance data.

env.glms.sand <- manyglm(formula.env.glms.sand,
                         data = env.sand,
                         family = "negative.binomial")

Explore the fit (residuals, diagnostic plots, etc.).

## residuals vs fitted values
plot(env.glms.sand)


## all traditional (g)lm diagnostic plots
plot.manyglm(env.glms.sand, which = 1:3)


# ### source mvabund GLM plotting functions modified to use a grey palette - I just can't redo these plots on my own, the function is doing too complicated things internally to scale the x and y axes
# source(here(functions.dir, "default.plot.manyglm_grey.R"))
# source(here(functions.dir, "plot.manyglm_grey.R"))
# 
# par(mfrow = c(2,2))
# lapply(1:3, function(i) plot.manyglm.grey(glms.lvm.sand, which = i, sub.caption = ""))
# par(mfrow = c(1, 1))

Well, it’s good enough if you ask me (still the kinda strange “line” at lin.pred = -6; otherwise residuals are random enough).

Save the model!

write_rds(env.glms.sand, 
          here(save.dir, "glms_env_sand.RDS"))

Before anything else, I want to try and reduce the model a little - to improve the fit/reduce run time.
The automatic step functions that eliminate/add model terms sequentially don’t work - they fail at the last step with a cryptic error about differing numbers of rows - I assume because manyglm has as left side term the whole community abundance matrix, and the functions don’t really know how to deal with that. I don’t understand enough about their internals to fix the problem, so I’m just going to write my own little automation based on the function drop1.

evaluate_glms_env <- function(full.mod) {
  ### sequentially eliminate model terms in manyglms vs environmental parameters, and find the best model based on lowest AIC score.
  ### Arguments: full.mod - full model fit
  ### Returns: best manyglm model of environmental parameters; prints out the best model formula
  ### Dependencies: tidyverse   
  

  ## get the starting formula (= full model with all variables)
  start.formula <- formula(full.mod)

  drop_var <- function(mod) {
    ### helper picking the next variable to drop from a model to improve the fit (based on AIC)
    
    ## check the model AICs if variables are dropped one by one
    drop1.df <- as_tibble(drop1(mod), rownames = "drop_var") %>% arrange(AIC)
    
    ## pick the variable to drop next - the one resulting in the largest decrease in AIC
    drop.var <- drop1.df %>% filter(AIC == min(AIC)) %>% pull(drop_var)
    return(drop.var)
  }
  
  ## pick the variable to drop next
  drop.var <- drop_var(full.mod)

  if(drop.var != "<none>") {
     ## update the model formula, dropping the variable resulting in the largest decrease in AIC; then apply it to the model.
    new.formula <- update.formula(start.formula, paste0("~. -", drop.var))
    new.mod <- update(full.mod, new.formula)

    ## identify a new variable to drop that lowers the AIC
    drop.var <- drop_var(new.mod)
    
    ## repeat the steps above until the function can no longer find such a variable (i.e., dropping more variables doesn't improve the model fit)
    while(drop.var != "<none>") {
      new.formula <- update.formula(new.formula, paste0("~. -", drop.var))
      new.mod <- update(full.mod, new.formula)
      drop.var <- drop_var(new.mod)
    }
    
    ## print out the best model formula
    print(paste("Best model: ", paste(deparse(new.formula), collapse = "")))
    return(new.mod)
    
  } else {
    ## if the starting model is the best, print its formula (fat chance!)
    print(paste("Best model: ", paste(deparse(start.formula), collapse = "")))
    return(full.mod)
  }
  
}

Select the best reduced model of environmental variables for the sand stations.

## selection function defined in the sand section 
top.env.glm.red.sand <- evaluate_glms_env(env.glms.sand)

Check its fit.

## residuals vs fitted values
plot(top.env.glm.red.sand)

## all traditional (g)lm diagnostic plots
plot.manyglm(top.env.glm.red.sand, which = 1:3)

I think it’s fine; might even be better than the full model.. Save it, too.

write_rds(top.env.glm.red.sand, 
          here(save.dir, "glms_top_env_red_sand.RDS"))

Run ANOVA on this model.

(top.env.glm.red.sand.aov <- anova.manyglm(top.env.glm.red.sand,
                                           test = "LR", p.uni = "adjusted",
                                           nBoot = 999, ## limit the number of permutations for a shorter run time   
                                           show.time = "all") 
)
Resampling begins for test 1.
    Resampling run 0 finished. Time elapsed: 0.01 minutes...
    Resampling run 100 finished. Time elapsed: 0.58 minutes...
    Resampling run 200 finished. Time elapsed: 1.18 minutes...
    Resampling run 300 finished. Time elapsed: 1.76 minutes...
    Resampling run 400 finished. Time elapsed: 2.35 minutes...
    Resampling run 500 finished. Time elapsed: 2.95 minutes...
    Resampling run 600 finished. Time elapsed: 3.56 minutes...
    Resampling run 700 finished. Time elapsed: 4.18 minutes...
    Resampling run 800 finished. Time elapsed: 4.79 minutes...
    Resampling run 900 finished. Time elapsed: 5.43 minutes...
Resampling begins for test 2.
    Resampling run 0 finished. Time elapsed: 0.00 minutes...
    Resampling run 100 finished. Time elapsed: 0.36 minutes...
    Resampling run 200 finished. Time elapsed: 0.73 minutes...
    Resampling run 300 finished. Time elapsed: 1.09 minutes...
    Resampling run 400 finished. Time elapsed: 1.47 minutes...
    Resampling run 500 finished. Time elapsed: 1.83 minutes...
    Resampling run 600 finished. Time elapsed: 2.21 minutes...
    Resampling run 700 finished. Time elapsed: 2.58 minutes...
    Resampling run 800 finished. Time elapsed: 2.95 minutes...
    Resampling run 900 finished. Time elapsed: 3.30 minutes...
Resampling begins for test 3.
    Resampling run 0 finished. Time elapsed: 0.00 minutes...
    Resampling run 100 finished. Time elapsed: 0.35 minutes...
    Resampling run 200 finished. Time elapsed: 0.70 minutes...
    Resampling run 300 finished. Time elapsed: 1.04 minutes...
    Resampling run 400 finished. Time elapsed: 1.38 minutes...
    Resampling run 500 finished. Time elapsed: 1.73 minutes...
    Resampling run 600 finished. Time elapsed: 2.08 minutes...
    Resampling run 700 finished. Time elapsed: 2.43 minutes...
    Resampling run 800 finished. Time elapsed: 2.79 minutes...
    Resampling run 900 finished. Time elapsed: 3.15 minutes...
Resampling begins for test 4.
    Resampling run 0 finished. Time elapsed: 0.00 minutes...
    Resampling run 100 finished. Time elapsed: 0.32 minutes...
    Resampling run 200 finished. Time elapsed: 0.64 minutes...
    Resampling run 300 finished. Time elapsed: 0.95 minutes...
    Resampling run 400 finished. Time elapsed: 1.27 minutes...
    Resampling run 500 finished. Time elapsed: 1.58 minutes...
    Resampling run 600 finished. Time elapsed: 1.89 minutes...
    Resampling run 700 finished. Time elapsed: 2.20 minutes...
    Resampling run 800 finished. Time elapsed: 2.51 minutes...
    Resampling run 900 finished. Time elapsed: 2.83 minutes...
Time elapsed: 0 hr 16 min 18 sec
Analysis of Deviance Table

Model: manyglm(formula = zoo.mvabnd.sand ~ PO4 + seston + LUSI + gravel, 
Model:     family = "negative.binomial", data = env.sand)

Multivariate test:
            Res.Df Df.diff    Dev Pr(>Dev)    
(Intercept)     53                            
PO4             52       1 1147.2    0.001 ***
seston          51       1  816.4    0.001 ***
LUSI            50       1  728.5    0.001 ***
gravel          49       1 1128.7    0.001 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Univariate Tests:
            Abra.alba          Abra.sp.          Acanthocardia.tuberculata         
                  Dev Pr(>Dev)      Dev Pr(>Dev)                       Dev Pr(>Dev)
(Intercept)                                                                        
PO4             1.011    1.000    0.513    1.000                     3.576    0.979
             Acari          Actiniaria          Alitta.succinea         
               Dev Pr(>Dev)        Dev Pr(>Dev)             Dev Pr(>Dev)
(Intercept)                                                             
PO4         10.498    0.120      0.513    1.000           0.065    1.000
            Ampelisca.diadema          Amphibalanus.improvisus          Amphipoda
                          Dev Pr(>Dev)                     Dev Pr(>Dev)       Dev
(Intercept)                                                                      
PO4                    12.592    0.032                  11.462    0.081     0.552
                     Amphitritides.gracilis          Ampithoe.sp.         
            Pr(>Dev)                    Dev Pr(>Dev)          Dev Pr(>Dev)
(Intercept)                                                               
PO4            1.000                  2.571    1.000        0.032    1.000
            Anadara.kagoshimensis          Aonides.paucibranchiata         
                              Dev Pr(>Dev)                     Dev Pr(>Dev)
(Intercept)                                                                
PO4                        67.791    0.001                   5.965    0.659
            Apseudopsis.ostroumovi          Aricidea.claudiae         
                               Dev Pr(>Dev)               Dev Pr(>Dev)
(Intercept)                                                           
PO4                          0.375    1.000             7.633    0.402
            Bathyporeia.guilliamsoniana          Bittium.reticulatum         
                                    Dev Pr(>Dev)                 Dev Pr(>Dev)
(Intercept)                                                                  
PO4                               0.002    1.000              22.784    0.002
            Bodotria.arenosa          Brachynotus.sexdentatus         
                         Dev Pr(>Dev)                     Dev Pr(>Dev)
(Intercept)                                                           
PO4                      1.3    1.000                  11.298    0.085
            Brachystomia.scalaris          Branchiostoma.lanceolatum         
                              Dev Pr(>Dev)                       Dev Pr(>Dev)
(Intercept)                                                                  
PO4                         0.696    1.000                     0.057    1.000
            Caecum.armoricum          Caecum.trachea          Capitella.capitata
                         Dev Pr(>Dev)            Dev Pr(>Dev)                Dev
(Intercept)                                                                     
PO4                    7.463    0.427          1.119    1.000              1.193
                     Capitella.minima          Cardiidae          Cerastoderma.edule
            Pr(>Dev)              Dev Pr(>Dev)       Dev Pr(>Dev)                Dev
(Intercept)                                                                         
PO4            1.000             2.53    1.000     0.513    1.000              7.708
                     Cerastoderma.glaucum          Chamelea.gallina         
            Pr(>Dev)                  Dev Pr(>Dev)              Dev Pr(>Dev)
(Intercept)                                                                 
PO4            0.384                1.415    1.000           27.316    0.001
            Chondrochelia.savignyi          Crassicorophium.crassicorne         
                               Dev Pr(>Dev)                         Dev Pr(>Dev)
(Intercept)                                                                     
PO4                          1.246    1.000                       0.459    1.000
            Cumopsis.goodsir          Cytharella.costulata          Decapoda.larvae
                         Dev Pr(>Dev)                  Dev Pr(>Dev)             Dev
(Intercept)                                                                        
PO4                    3.576    0.969               16.556    0.008           4.389
                     Dinophilus.gyrociliatus          Diogenes.pugilator         
            Pr(>Dev)                     Dev Pr(>Dev)                Dev Pr(>Dev)
(Intercept)                                                                      
PO4            0.845                   3.462    0.988              2.328    1.000
            Donax.venustus          Elaphognathia.bacescoi          Eteone.flava
                       Dev Pr(>Dev)                    Dev Pr(>Dev)          Dev
(Intercept)                                                                     
PO4                 11.663    0.069                  1.021    1.000        7.158
                     Eteone.sp.          Eulalia.viridis          Eunice.vittata
            Pr(>Dev)        Dev Pr(>Dev)             Dev Pr(>Dev)            Dev
(Intercept)                                                                     
PO4            0.480      3.247    0.996           0.508    1.000          5.957
                     Eurydice.dollfusi          Eurydice.pontica         
            Pr(>Dev)               Dev Pr(>Dev)              Dev Pr(>Dev)
(Intercept)                                                              
PO4            0.659             7.553    0.419            0.243    1.000
            Exogone.naidina          Gammaridae          Gastrosaccus.sanctus         
                        Dev Pr(>Dev)        Dev Pr(>Dev)                  Dev Pr(>Dev)
(Intercept)                                                                           
PO4                   1.544    1.000      0.215    1.000                0.001    1.000
            Genetyllis.tuberculata          Glycera.sp.          Glycera.tridactyla
                               Dev Pr(>Dev)         Dev Pr(>Dev)                Dev
(Intercept)                                                                        
PO4                          9.748    0.149       1.819    1.000              4.038
                     Harmothoe.imbricata          Harmothoe.reticulata         
            Pr(>Dev)                 Dev Pr(>Dev)                  Dev Pr(>Dev)
(Intercept)                                                                    
PO4            0.882               7.572    0.416                6.871    0.582
            Heteromastus.filiformis          Hirudinea          Holothuroidea         
                                Dev Pr(>Dev)       Dev Pr(>Dev)           Dev Pr(>Dev)
(Intercept)                                                                           
PO4                          55.658    0.001     4.073    0.876         6.327    0.634
            Hydrobia.acuta          Hydrobia.sp.          Iphinoe.sp.         
                       Dev Pr(>Dev)          Dev Pr(>Dev)         Dev Pr(>Dev)
(Intercept)                                                                   
PO4                  3.566    0.988        3.379    0.993       0.243    1.000
            Iphinoe.tenella          Kellia.suborbicularis          Lagis.koreni
                        Dev Pr(>Dev)                   Dev Pr(>Dev)          Dev
(Intercept)                                                                     
PO4                  38.241    0.001                12.137    0.052       48.067
                     Leiochone.leiopygos          Lentidium.mediterraneum         
            Pr(>Dev)                 Dev Pr(>Dev)                     Dev Pr(>Dev)
(Intercept)                                                                       
PO4            0.001              20.554    0.003                  16.232    0.009
            Leptosynapta.inhaerens          Lindrilus.flavocapitatus         
                               Dev Pr(>Dev)                      Dev Pr(>Dev)
(Intercept)                                                                  
PO4                          3.875    0.905                    4.746    0.795
            Loripes.orbiculatus          Lucinella.divaricata          Lysidice.ninetta
                            Dev Pr(>Dev)                  Dev Pr(>Dev)              Dev
(Intercept)                                                                            
PO4                      14.871    0.012               19.259    0.004            0.243
                     Mactra.stultorum          Magelona.papillicornis         
            Pr(>Dev)              Dev Pr(>Dev)                    Dev Pr(>Dev)
(Intercept)                                                                   
PO4            1.000            2.401    1.000                 19.059    0.004
            Magelona.rosea          Maldanidae          Melinna.palmata         
                       Dev Pr(>Dev)        Dev Pr(>Dev)             Dev Pr(>Dev)
(Intercept)                                                                     
PO4                   4.77    0.795      3.576    0.979          75.355    0.001
            Melita.palmata          Microdeutopus.gryllotalpa          Microdeutopus.sp.
                       Dev Pr(>Dev)                       Dev Pr(>Dev)               Dev
(Intercept)                                                                             
PO4                 14.255    0.019                     0.001    1.000             3.576
                     Microdeutopus.versiculatus          Micromaldane.ornithochaeta
            Pr(>Dev)                        Dev Pr(>Dev)                        Dev
(Intercept)                                                                        
PO4            0.971                       9.28    0.172                     10.809
                     Micronephthys.stammeri          Microphthalmus.fragilis         
            Pr(>Dev)                    Dev Pr(>Dev)                     Dev Pr(>Dev)
(Intercept)                                                                          
PO4            0.098                  0.016    1.000                   0.028    1.000
            Microphthalmus.sp.          Monocorophium.acherusicum         
                           Dev Pr(>Dev)                       Dev Pr(>Dev)
(Intercept)                                                               
PO4                      8.692    0.220                     3.627    0.966
            Monocorophium.insidiosum          Mysta.picta          Mytilaster.lineatus
                                 Dev Pr(>Dev)         Dev Pr(>Dev)                 Dev
(Intercept)                                                                           
PO4                            7.646    0.401       4.088    0.876               9.876
                     Mytilus.galloprovincialis          Neanthes.sp.          Nemertea
            Pr(>Dev)                       Dev Pr(>Dev)          Dev Pr(>Dev)      Dev
(Intercept)                                                                           
PO4            0.143                     0.507    1.000        1.415    1.000    0.718
                     Nephtyidae          Nephtys.cirrosa          Nereididae         
            Pr(>Dev)        Dev Pr(>Dev)             Dev Pr(>Dev)        Dev Pr(>Dev)
(Intercept)                                                                          
PO4            1.000      3.733    0.931           3.455    0.989      0.243    1.000
            Nereis.pelagica          Nereis.perivisceralis          Nereis.pulsatoria
                        Dev Pr(>Dev)                   Dev Pr(>Dev)               Dev
(Intercept)                                                                          
PO4                   1.278    1.000                 5.021    0.764              1.04
                     Nototropis.guttatus          Odostomia.plicata          Oligochaeta
            Pr(>Dev)                 Dev Pr(>Dev)               Dev Pr(>Dev)         Dev
(Intercept)                                                                             
PO4            1.000               0.017    1.000             2.158    1.000      12.804
                     Ophelia.limacina          Papillicardium.papillosum         
            Pr(>Dev)              Dev Pr(>Dev)                       Dev Pr(>Dev)
(Intercept)     <NA>             <NA>     <NA>                      <NA>     <NA>
PO4            0.032             1.13    1.000                     1.026    1.000
            Paradoneis.harpagonea          Parthenina.interstincta         
                              Dev Pr(>Dev)                     Dev Pr(>Dev)
(Intercept)                  <NA>     <NA>                    <NA>     <NA>
PO4                        16.021    0.009                   0.628    1.000
            Parvicardium.exiguum          Perinereis.cultrifera         
                             Dev Pr(>Dev)                   Dev Pr(>Dev)
(Intercept)                 <NA>     <NA>                  <NA>     <NA>
PO4                        14.43    0.013                 6.906    0.582
            Perioculodes.longimanus          Pestarella.candida          Pholoe.inornata
                                Dev Pr(>Dev)                Dev Pr(>Dev)             Dev
(Intercept)                    <NA>     <NA>               <NA>     <NA>            <NA>
PO4                          13.283    0.026              1.021    1.000           2.532
                     Phoronida          Phyllodoce.sp.          Pisces.larvae         
            Pr(>Dev)       Dev Pr(>Dev)            Dev Pr(>Dev)           Dev Pr(>Dev)
(Intercept)     <NA>      <NA>     <NA>           <NA>     <NA>          <NA>     <NA>
PO4            1.000    14.128    0.020          0.214    1.000         3.566    0.979
            Pisione.remota          Pitar.rudis          Platyhelminthes         
                       Dev Pr(>Dev)         Dev Pr(>Dev)             Dev Pr(>Dev)
(Intercept)           <NA>     <NA>        <NA>     <NA>            <NA>     <NA>
PO4                  0.184    1.000        2.33    1.000           1.258    1.000
            Platynereis.dumerilii          Polititapes.aureus          Polychaeta.larvae
                              Dev Pr(>Dev)                Dev Pr(>Dev)               Dev
(Intercept)                  <NA>     <NA>               <NA>     <NA>              <NA>
PO4                          2.51    1.000              5.232    0.758             0.667
                     Polycirrus.caliendrum          Polycirrus.jubatus         
            Pr(>Dev)                   Dev Pr(>Dev)                Dev Pr(>Dev)
(Intercept)     <NA>                  <NA>     <NA>               <NA>     <NA>
PO4            1.000                 8.778    0.213             14.046    0.021
            Polydora.ciliata          Polygordius.neapolitanus         
                         Dev Pr(>Dev)                      Dev Pr(>Dev)
(Intercept)             <NA>     <NA>                     <NA>     <NA>
PO4                    33.47    0.001                    1.738    1.000
            Prionospio.cirrifera          Protodorvillea.kefersteini         
                             Dev Pr(>Dev)                        Dev Pr(>Dev)
(Intercept)                 <NA>     <NA>                       <NA>     <NA>
PO4                       48.371    0.001                      2.268    1.000
            Protodrilus.sp.          Pseudocuma.longicorne          Rapana.venosa
                        Dev Pr(>Dev)                   Dev Pr(>Dev)           Dev
(Intercept)            <NA>     <NA>                  <NA>     <NA>          <NA>
PO4                   0.497    1.000                13.533    0.024        16.327
                     Retusa.truncatula          Retusa.variabilis         
            Pr(>Dev)               Dev Pr(>Dev)               Dev Pr(>Dev)
(Intercept)     <NA>              <NA>     <NA>              <NA>     <NA>
PO4            0.008             0.513    1.000              4.77    0.795
            Rhithropanopeus.harrisii          Rissoa.membranacea         
                                 Dev Pr(>Dev)                Dev Pr(>Dev)
(Intercept)                     <NA>     <NA>               <NA>     <NA>
PO4                            1.021    1.000              2.111    1.000
            Sabellaria.taurica          Salvatoria.clavata         
                           Dev Pr(>Dev)                Dev Pr(>Dev)
(Intercept)               <NA>     <NA>               <NA>     <NA>
PO4                     16.327    0.008              2.946    0.999
            Schistomeringos.rudolphi          Sphaerosyllis.hystrix         
                                 Dev Pr(>Dev)                   Dev Pr(>Dev)
(Intercept)                     <NA>     <NA>                  <NA>     <NA>
PO4                           11.176    0.087                 3.042    0.998
            Spio.filicornis          Spionidae          Spisula.subtruncata         
                        Dev Pr(>Dev)       Dev Pr(>Dev)                 Dev Pr(>Dev)
(Intercept)            <NA>     <NA>      <NA>     <NA>                <NA>     <NA>
PO4                   8.141    0.262     0.278    1.000              34.272    0.001
            Stenothoe.monoculoides          Sternaspis.scutata         
                               Dev Pr(>Dev)                Dev Pr(>Dev)
(Intercept)                   <NA>     <NA>               <NA>     <NA>
PO4                          1.021    1.000              0.497    1.000
            Steromphala.divaricata          Streptosyllis.bidentata         
                               Dev Pr(>Dev)                     Dev Pr(>Dev)
(Intercept)                   <NA>     <NA>                    <NA>     <NA>
PO4                           3.62    0.966                  14.133    0.020
            Syllis.gracilis          Syllis.hyalina          Tellina.fabula         
                        Dev Pr(>Dev)            Dev Pr(>Dev)            Dev Pr(>Dev)
(Intercept)            <NA>     <NA>           <NA>     <NA>           <NA>     <NA>
PO4                   1.059    1.000         11.199    0.086          7.846    0.291
            Tellina.tenuis          Tritia.neritea          Tritia.reticulata         
                       Dev Pr(>Dev)            Dev Pr(>Dev)               Dev Pr(>Dev)
(Intercept)           <NA>     <NA>           <NA>     <NA>              <NA>     <NA>
PO4                  5.219    0.758          9.738    0.149             7.578    0.416
            Turbellaria          Upogebia.pusilla         
                    Dev Pr(>Dev)              Dev Pr(>Dev)
(Intercept)        <NA>     <NA>             <NA>     <NA>
PO4               0.973    1.000            1.021    1.000
 [ reached getOption("max.print") -- omitted 3 rows ]
Arguments:
 Test statistics calculated assuming uncorrelated response (for faster computation) 
P-value calculated using 999 resampling iterations via PIT-trap resampling (to account for correlation in testing.

So, it turns out that the long-term water column eutrophication (PO4, seston), the anthropogenic pressure in general (LUSI), and the sediment composition (gravel) explain the observed community patterns best.

Save the ANOVA - I really, really don’t want to have to repeat it.

write_rds(top.env.glm.red.sand.aov, 
          here(save.dir, "glms_top_env_red_sand_anova.RDS"))

Get the taxa with the highest contributions to the tested pattern (here - species most affected by changes in water/environmental quality parameters).

## get the top contributing species for the environmental parameter sand GLMs 
(top.sp.glms.env.red.sand <- top_n_sp_glm(top.env.glm.red.sand.aov, tot.dev.expl = 0.75)
)
[1] "Total deviance explained: 0.817"
           Melinna.palmata      Anadara.kagoshimensis    Heteromastus.filiformis 
                 75.354817                  67.790515                  55.657621 
      Prionospio.cirrifera               Lagis.koreni            Iphinoe.tenella 
                 48.371413                  48.067236                  38.240757 
       Spisula.subtruncata           Polydora.ciliata           Chamelea.gallina 
                 34.272034                  33.469990                  27.316472 
       Bittium.reticulatum        Leiochone.leiopygos       Lucinella.divaricata 
                 22.783736                  20.553990                  19.259453 
    Magelona.papillicornis       Cytharella.costulata         Sabellaria.taurica 
                 19.059044                  16.556175                  16.326603 
             Rapana.venosa    Lentidium.mediterraneum      Paradoneis.harpagonea 
                 16.326603                  16.231882                  16.021000 
       Loripes.orbiculatus       Parvicardium.exiguum             Melita.palmata 
                 14.870959                  14.429942                  14.255372 
   Streptosyllis.bidentata                  Phoronida         Polycirrus.jubatus 
                 14.133303                  14.128398                  14.045827 
     Pseudocuma.longicorne    Perioculodes.longimanus                Oligochaeta 
                 13.533423                  13.282665                  12.804148 
         Ampelisca.diadema      Kellia.suborbicularis             Donax.venustus 
                 12.591581                  12.137452                  11.662509 
   Amphibalanus.improvisus    Brachynotus.sexdentatus             Syllis.hyalina 
                 11.462125                  11.298400                  11.198693 
  Schistomeringos.rudolphi Micromaldane.ornithochaeta                      Acari 
                 11.176121                  10.809322                  10.498478 
       Mytilaster.lineatus     Genetyllis.tuberculata             Tritia.neritea 
                  9.875996                   9.747742                   9.737885 
Microdeutopus.versiculatus      Polycirrus.caliendrum         Microphthalmus.sp. 
                  9.280497                   8.778395                   8.692123 
           Spio.filicornis             Tellina.fabula         Cerastoderma.edule 
                  8.140655                   7.845543                   7.707880 
  Monocorophium.insidiosum          Aricidea.claudiae          Tritia.reticulata 
                  7.646026                   7.632964                   7.577649 
       Harmothoe.imbricata          Eurydice.dollfusi 
                  7.571700                   7.553233 
## unfortunately, mvabund likes to rename my species when converting the data to matrix (no spaces in names), and since I'm going to look them up in my initial untransformed count data, I have to change them back..   DON'T BE IN A HURRY TO DO THAT IF YOU WANT TO SUBSET THE ORIGINAL MATRIX BEFORE RUNNING TRAITGLM 
names(top.sp.glms.env.red.sand) <- names(top.sp.glms.env.red.sand) %>% 
  str_replace(pattern = "\\.", replacement = " ")

I’m going to plot these top contributing species, but I’m not using the plot. At least this time it’s more manageable, but still not presentable enough..

## get the species and their abundances from the original count data, and transform them to long format
abnd.top.sp.glms.env.red.sand <- zoo.abnd.sand %>% 
  select(station, names(top.sp.glms.env.red.sand)) %>% 
  gather(key = "species", value = "count", -station) %>% 
  ## turn species into a factor, or you'll be very very sorry later, when they're out of order on the plot. NB need to be in REVERSE order, because ggplot plots from bottom to top, and I want the top-contributing species on top. 
  mutate(species = factor(species, levels = rev(names(top.sp.glms.env.red.sand)))) %>% 
  ## add clusters from LVM as a column
  mutate(group = case_when(station %in% c("Kraimorie", "Chukalya") ~ 1,
                           station == "Akin" ~ 2, 
                           station %in% c("Sozopol", "Paraskeva") ~ 3, 
                           station == "Agalina" ~ 4))
## add the significant environmental parameters from the model
(abnd.top.sp.glms.env.red.sand <- left_join(abnd.top.sp.glms.env.red.sand, 
                                            env.sand %>% select(station, PO4, seston, LUSI, gravel), 
                                            by = "station") 
    
)
(plot.top.sp.glms.env.red.sand <- plot_top_n(abnd.top.sp.glms.env.red.sand,
                                             mapping = aes(x = species, y = log_y_min(count), colour = factor(group)),
                                             labs.legend = unique(abnd.top.sp.glms.env.red.sand$group),
                                             lab.y = "Abundance (log(y/min + 1))",
                                             palette = "Set2") + 
    theme(legend.position = "top")
)

FIXME>>> Try another thing - manually, unfortunately: this same nightmare, but colored by the values of each model term.

Extract the taxon information (univariate tests) from the model ANOVA to present as a table (probably better than this plot, although it’s informative).

## extract the univariate test coefficients (LR) from the environmental model ANOVA. NB keep the row names when converting the matrix to tibble! 
table.top.sp.glms.env.red.sand <- as_tibble(top.env.glm.red.sand.aov$uni.test, rownames = "var")
## fix the species names - remove first dor  
names(table.top.sp.glms.env.red.sand) <- names(table.top.sp.glms.env.red.sand) %>% 
  str_replace(pattern = "\\.", replacement = " ")
## subset only the top species (explaining ~75% of the dataset variation)
table.top.sp.glms.env.red.sand <- table.top.sp.glms.env.red.sand %>% 
  select(var, names(top.sp.glms.env.red.sand))
## transpose, because a table with 50 columns is just unreadable
(table.top.sp.glms.env.red.sand <- table.top.sp.glms.env.red.sand %>%
    gather(key = species, value = value, -var) %>% 
    spread(key = var, value = value) %>% 
    ## arrange as before (terms in the order they appear in the model, and by descending value of the LR for the first model term - here, PO4). Also get rid of the intercept (it's all-NA anyway).
    select(species, PO4, seston, LUSI, gravel) %>%
    arrange(desc(PO4)) 
)

Save this to a file - will have to format it as a nice table by hand, unfortunately.

write_csv(table.top.sp.glms.env.red.sand, 
          here(save.dir, "taxa_contrib_glms_top_env_red_sand.csv"))

Calculate the percentage contribution of each of these species to each of the model terms (Dev(term) = Sum-of-LR - sum of the LRs for the individual univariate species tests)..

## get the total deviance (Sum-of-LR) for each model term
(dev.terms.top.glms.env.sand <- as_tibble(top.env.glm.red.sand.aov$table, rownames = "var") %>%
   ## get rid of unnecessary variables (I only want the deviance value for each term) and intercept term 
   select(var, Dev) %>% 
   filter(var != "(Intercept)") %>% 
   ## transpose 
   gather(variable, value, -var) %>%
   spread(var, value) %>% 
   ## get rid of first column and rearrange columns to match table of deviances of univariate tests for species 
   select(-variable) %>% 
   select(PO4, seston, LUSI, gravel)
)  
## calculate the proportion contribution of each species to each parameter deviance
prop.top.sp.glms.env.red.sand <- map2_df(table.top.sp.glms.env.red.sand %>% select(-species),
                                         dev.terms.top.glms.env.sand, 
                                         ~.x/.y)
## add back the species 
(prop.top.sp.glms.env.red.sand <- bind_cols(table.top.sp.glms.env.red.sand %>% select(species), 
                                            prop.top.sp.glms.env.red.sand)
)

Final analysis to try: which species respond differently to different environmental parameters? (= traits analysis - fit single predictive model for all species at all sites, but w/o attempting to explain the different responses using traits - the species ID is used in place of a traits matrix).
NB only use the top species that exhibited a reaction in the environmental model fit (= the ones accounting for ~75% of the total variability), and only the significant predictors - to improve run times.

sp.response.glms.env.red.sand <- traitglm(L = mvabund(zoo.abnd.flt.sand[, names(top.sp.glms.env.red.sand)]), 
                                          R = as.matrix(env.sand %>% select(PO4, seston, LUSI, gravel)), 
                                          method = "manyglm")
No traits matrix entered, so will fit SDMs with different env response for each spp 
sp.response.glms.env.red.sand$fourth.corner
                                            PO4      seston          LUSI       gravel
names.L.Ampelisca.diadema             3.9255509  -2.9690187  -0.817892764  -0.54638276
names.L.Amphibalanus.improvisus       4.0226904  -3.2428168  -0.613822194  -0.55947227
names.L.Anadara.kagoshimensis        11.2652127  -7.5624621  -2.881581827  -0.56229429
names.L.Aricidea.claudiae             6.4545107  -6.0030102   0.075837116  -0.81658105
names.L.Bittium.reticulatum           3.6728293  -3.2566010  -0.227682651  -0.60908662
names.L.Brachynotus.sexdentatus      12.2714488  -8.7953746  -2.768356521  -1.15909023
names.L.Cerastoderma.edule           86.3144545 -68.5410436 -16.124587996 -15.76009706
names.L.Chamelea.gallina              4.9735567  -4.0806520  -0.915304631  -0.90870404
names.L.Cytharella.costulata          5.9066074  -4.5531016  -1.156170995  -0.64061054
names.L.Donax.venustus               29.2665146 -25.3133054  -3.196472244  -7.48930781
names.L.Eurydice.dollfusi          -145.3134807  78.0140182  56.500452934  -1.12048695
names.L.Genetyllis.tuberculata        4.9508698  -4.4226734  -0.717237975  -0.50545895
names.L.Harmothoe.imbricata           8.7688494  -8.0381252  -0.174424875  -1.40001396
names.L.Heteromastus.filiformis      16.4489612 -11.8603189  -4.679979720  -0.53453476
names.L.Iphinoe.tenella               9.6429106  -6.3711957  -2.467970830  -0.34728546
names.L.Kellia.suborbicularis        18.1479826 -13.1444944  -4.028384566  -2.38364695
names.L.Lagis.koreni                  5.2752482  -3.9409882  -1.063633817  -0.49005707
names.L.Leiochone.leiopygos           9.4458023  -7.0107877  -2.426883847  -0.49499547
names.L.Lentidium.mediterraneum       2.2184223  -7.7274293   5.119259705  -3.80721597
names.L.Loripes.orbiculatus          11.9138363 -10.5152606  -1.772124177  -1.53849109
names.L.Lucinella.divaricata          4.3089522  -3.8383729  -0.941760570  -0.90040958
names.L.Magelona.papillicornis       -0.8618886  -1.6184538   2.126924166  -1.13824665
names.L.Melinna.palmata              87.5950547 -62.3176332 -28.320862498  -0.53785792
names.L.Melita.palmata               -1.4068078  -1.4310911   2.175555342   0.04534594
names.L.Microdeutopus.versiculatus    4.5619062  -3.3188059  -1.480537959   0.01704370
names.L.Micromaldane.ornithochaeta    2.0293951  -3.6054716   1.146677297  -1.10488159
names.L.Microphthalmus.sp.            2.4219932  -2.3771910  -0.331905804  -0.45014535
names.L.Monocorophium.insidiosum     91.2704372 -72.4819591 -16.997678796 -16.75142841
names.L.Mytilaster.lineatus           3.6452068  -3.0310816  -0.453771212  -0.56603117
names.L.Oligochaeta                   1.1142783  -0.9168759   0.182815777  -0.26804214
names.L.Paradoneis.harpagonea        44.6268239 -34.6189865 -10.110156651  -6.18181742
names.L.Parvicardium.exiguum          5.4679515  -4.2901258  -1.071674867  -0.60043740
names.L.Perioculodes.longimanus       3.8233980  -3.1155895  -0.537523634  -0.55747087
names.L.Phoronida                     4.3674755  -4.1186121  -0.107432136  -0.69239101
names.L.Polycirrus.caliendrum       -14.6362720 -14.5110317  24.537891679  -3.49252794
names.L.Polycirrus.jubatus           -2.4679942  -2.7467481   4.271575754  -0.36118532
names.L.Polydora.ciliata              5.8538836  -4.5251508  -1.054314612  -0.53519651
names.L.Prionospio.cirrifera          4.6312252  -3.5794420  -0.682191827  -0.61411757
names.L.Pseudocuma.longicorne      -184.7247688  94.1777708  77.116820970  -2.87857061
names.L.Rapana.venosa                 6.2536074  -5.8242086   0.109640812  -0.74952507
names.L.Sabellaria.taurica            6.4201209  -5.9779189   0.094454203  -0.79630833
names.L.Schistomeringos.rudolphi      8.9818953  -6.6900990  -3.539271831  -0.05466283
names.L.Spio.filicornis              23.9025062 -18.4529248  -3.775190226  -6.60866099
names.L.Spisula.subtruncata           8.3692147  -6.4982724  -1.857417192  -1.49042998
names.L.Streptosyllis.bidentata      -1.7193139  -2.0772085   3.037260251  -0.16308400
names.L.Syllis.hyalina               -1.4595610  -2.6762110   3.349712166  -0.32574204
names.L.Tellina.fabula               91.2704372 -72.4819591 -16.997678816 -16.75142841
names.L.Tritia.neritea               -3.8087181  -2.4272915   5.454585358  -1.65134985
names.L.Tritia.reticulata             2.6224780  -1.4687956   0.003212383  -0.74189472
# plot this 
a <- max(abs(sp.response.glms.env.red.sand$fourth.corner))
colort <- colorRampPalette(c("blue","white","red")) 
plot.spp <- lattice::levelplot(t(as.matrix(sp.response.glms.env.red.sand$fourth.corner)), xlab = "Environmental Variables",
                     ylab = "Species", col.regions = colort(100), at = seq(-a, a, length = 100),
                     scales = list(x = list(rot = 45)))
print(plot.spp)

When using LASSO (method = “glm1path”), the algorithm fails to converge - I’m not sure how to interpret it.. Maybe because the function tests each individual species:env.parameter interaction (does it really??), and none of them by themselves are sufficient to explain a species’ response. Not to mention the fact that the samples are not really independent (they are replicates at 6 sites, repeated 3 times).
When using method = “manyglm”, the result is the one shown above. It’s still a bitch to interpret - for example, what is the interpretation of an increase in abundance with for ex. high PO4, but low LUSI? Where are these conditions ever met?

In fact, everything points towards the conclusion that a species response is determined by a combination of eutrophication parameters in its environment (water column characteristics), and the composition of the sediments (organic matter and granulometry).

This is actually sort of similar to the PERMANOVA results, in this particular case. However, it’s much more parsimonious.
In the future, I’m leaning more towards the modeling approach - it allows you to check the model fit to one’s real data; also, there are no data reductions due to calculation of distance matrices.

Seagrass stations (Burgas Bay, 2013-2014)

Import zoobenthic abundance data (cleaned and prepared).

zoo.abnd.zostera <- read_csv(here(save.dir, "abnd_zostera_orig_clean.csv"))

## convert station to factor (better safe than sorry later, when the stations are not plotted in the order I want them)
(zoo.abnd.zostera <- zoo.abnd.zostera %>% 
    mutate(station = factor(station, levels = c("Poda", "Otmanli", "Vromos", "Gradina", "Ropotamo")))
)

Remove the all-0 species (= not present in the current dataset).
Maybe also remove the singletons (species appearing only once in the whole dataset and represented by a single individual = so rare that it’s unlikely they carry important information, but it would probably improve the run times).

(zoo.abnd.flt.zostera <- zoo.abnd.zostera %>%
   select(-c(station:replicate)) %>%
   select(which(colSums(.) > 0))
)
LVM - model-based ordination

Perform a model-based unconstrained ordination by fiting a pure latent variable model (package boral - Hui et al., 2014). This will allow to visualize the multivariate stations x species data - similar to nMDS, can be interpreted in the same way.
I’m including a (fixed) row effect to account for differences in site total abundance - this way, the ordination is in terms of species composition.
NB this takes about a million years to run!

lvm.zostera <- boral(y = zoo.abnd.flt.zostera, 
                  family = "negative.binomial",
                  
                  ## we want to control for site effects - there are 6 sites with 9 replicates each
                  row.eff = "fixed", row.ids = matrix(rep(1:5, times = c(8, 8, 4, 8, 4)), ncol = 1),  
                  ## 2 latent variables = 2 axes on which to represent the zoobenthic data
                  lv.control = list(num.lv = 2) 
                  
     #              ## example control structure, to check if function does what I want, because otherwise it takes an intolerably long time, and I'll shoot myself if I have to wait for it again
     #              mcmc.control = list(n.burnin = 10, n.iteration = 100,
     # n.thin = 1)
     #              
     
                  )

Check the summary and diagnostic plots for the LVM.

summary(lvm.zostera)

## model fit diagnostic plots
plot(lvm.zostera) 

The residuals plots look fine (no patterns in the residuals vs fitted, so variance is homogeneous, the quantile plot shows a (more or less) normal distribution of the residuals) - the model fits the data pretty well.

Save the zostera LVM.

write_rds(lvm.zostera, 
          here(save.dir, "lvm_zostera.RDS"))

Examine the biplot obtained by fitting the LVM, as well as the 20 most “important” species.

lvsplot(lvm.zostera, jitter = T, biplot = TRUE, ind.spp = 20)

All in all, the final result resembles the nMDS ordination very much - same stretched clusters (Poda + Otmanli, Vromos pretty much apart, Gradina +- Ropotamo). I don’t see much difference with the nMDS. The main difference seems to be the distance between the 2 years for Poda ana Otmanli - the LVM enlarges it. Have to remember to test for year effect! The run time is actually not that bad for the seagrasses. The species singled out as significant are probably somewhat different - have to check!

Redo the biplot, because this one is not very pretty. I’m not adding the species on top, first because I’m too lazy to figure out the procedure for ordering them, and second because the plot gets too busy.

## extract the LV coordinates of the stations from the model, so that the plot can be redone in ggplot 
lvs.coord.zostera <- as_tibble(lvm.zostera$lv.median)

## add the stations from the original zoobenthic table (order was not modified)
(lvs.coord.zostera <- lvs.coord.zostera %>% 
  bind_cols(zoo.abnd.zostera %>% select(station))
)

Make the plot and save it.

(plot.lvm.zostera <- ggplot(lvs.coord.zostera) + 
    geom_point(aes(x = lv1, y = lv2, colour = station)) + 
    scale_color_brewer(palette = "Set2", name = "station", 
                       labels = paste0("Z", as.numeric((unique(lvs.coord.zostera %>% pull(station)))))) +
   labs(x = "LV1", y = "LV2")
)

Well, this is a weird one - this plot is flipped around 0 compared to the one that boral’s plotting function gives. Otherwise nothing changes - the spatial relationships between samples are preserved. I suppose it doesn’t matter much - the axes are arbitrary after all, but strange that it happens.

## save the LVM plot for the seagrass
ggsave(file = here(figures.dir, "lvm_zostera.png"), 
       plot.lvm.zostera, 
       width = 15, units = "cm", dpi = 300)
GLM fitting for abundance - environmental data

Fit GLMs to the sites x species matrix to try and explain the observed differences in community structure by the variation of the environmental parameters.
These functions all come from package mvabund.
Import the environmental data - the one cleaned, prepared and saved in the previous notebook (classical multivariate methods). It contains long-term averages for the water column data (as long-term as available, at least) at each station, repeated for each replicate, the sediment data (2013-2014), and the seagrass data (2013-2014), again repeated to the same number of replicates. Only the variables determined to be significant by PCA are kept.

env.zostera <- read_csv(here(save.dir, "env_data_ordinations_zostera.csv"))

## convert station to factor
(env.zostera <- env.zostera %>% 
    mutate(station = factor(station,
                            levels = c("Poda", "Otmanli", "Vromos", "Gradina", "Ropotamo")))
)

Station is a factor, the rest of the variables are numeric.

Turn the zoobenthic data (minus the all-0 taxa) into a matrix - easier for the mvabund package and methods to deal with.

## there is already one subset of filtered count data (32 x 94) - use it 
zoo.mvabnd.zostera <- mvabund(zoo.abnd.flt.zostera)
manyGLM by LVM clusters

First, let’s see if the groups from the latent variable model (more or less equal to the clusters from the classical ordination) are valid, and which species exhibit a response.
I’m going to try something new here - 1) loose clusters from the LVM ordination, 1 = Poda-Otmanli, 2 = Vromos, 3 = Gradina-Ropotamo. 2) stations as clusters, as I did before for the seagrass data, although I don’t believe it’s valid/justified to do so… 3) another configuration of clusters from the LVM ordination: 1 = Z1-Z2, 2 = Z3, 3 = Z4, 4 = Z5.

## construct the vectors of the clusters by hand - first, situation 1 above
lvm.clusters.zostera.1 <- rep(1:3, times = c(16, 4, 12))
(lvm.clusters.zostera.1 <- factor(lvm.clusters.zostera.1))

## again, for case 2
lvm.clusters.zostera.2 <- rep(1:5, times = c(8, 8, 4, 8, 4))
(lvm.clusters.zostera.2 <- factor(lvm.clusters.zostera.2))

## again, for case 3
lvm.clusters.zostera.3 <- rep(1:4, times = c(16, 4, 8, 4))
(lvm.clusters.zostera.3 <- factor(lvm.clusters.zostera.3))

LVM clusters - case 1 Check the model assumptions. 1. Mean-variance assumption => determines the choice of family parameter. Can be checked by plotting residuals vs fits: if little pattern - the chosen mean-variance assumption is plausible.
Another way: direct plotting (variance ~ mean), for each species within each factor level.

plot(manyglm(zoo.mvabnd.zostera ~ lvm.clusters.zostera.1, family = "negative.binomial"))

meanvar.plot(zoo.mvabnd.zostera ~ lvm.clusters.zostera.1, table = TRUE)

It’s not perfect, but it’s not too terrible either.

  1. Assumed relationship between mean abundance and environmental variables - link function and formula. When quantitative variables are included in the model (for now, not relevant - will be in the next model) -> if there is a trend in size of residuals at different fitted values (e.g. U-shape,..) = violation of the log-linearity assumption.

Everything looks more or less fine; fit the model.

glms.lvm.zostera.1 <- manyglm(zoo.mvabnd.zostera ~ lvm.clusters.zostera.1, 
                              family = "negative.binomial")

Explore the fit (residuals, diagnostic plots, etc.).

## residuals vs fitted values
plot(glms.lvm.zostera.1)

## all traditional (g)lm diagnostic plots
plot.manyglm(glms.lvm.zostera.1, which = 1:3)

# ### source mvabund GLM plotting functions modified to use a grey palette - I just can't redo these plots on my own, the function is doing too complicated things internally to scale the x and y axes
# source(here(functions.dir, "default.plot.manyglm_grey.R"))
# source(here(functions.dir, "plot.manyglm_grey.R"))
# 
# par(mfrow = c(2,2))
# lapply(1:3, function(i) plot.manyglm.grey(glms.lvm.zostera, which = i, sub.caption = ""))
# par(mfrow = c(1, 1))

I really don’t like the rainbow palette, but I would like to include these plots in my thesis results.. Will have to do something about it, just not right now.
Save the model!

write_rds(glms.lvm.zostera.1, 
          here(save.dir, "glms_lvm_zostera_1.RDS"))

Let’s see the model summary (NB takes a LOT of time if there are many resamplings!).

(glms.lvm.zostera.1.summary <- summary(glms.lvm.zostera.1, 
                                  test = "LR", p.uni = "adjusted",
                                  nBoot = 999, ## limit the number of permutations if you just want to check it out
                                  show.time = "all")
)

The factor is highly significant according to the models.
This also allows us to see which species exhibit a response to the chosen factor. The LR (likelihood ratio) statistic is used as a measure of the strength of individual taxon contributions to the observed patterns. I’ll save the summary for safekeeping, but I’ll also run an anova - to get an analysis of deviance table on the model fit (also better for extracting the species contributions, or at least I know how to do it).

write_rds(glms.lvm.zostera.1.summary, 
          here(save.dir, "glms_lvm_zostera_1_summary.RDS"))

Run the anova on the model.

(glms.lvm.zostera.1.aov <- anova.manyglm(glms.lvm.zostera.1, 
                                    test = "LR", p.uni = "adjusted", 
                                    nBoot = 999, ## limit the number of permutations for a shorter run time
                                    pairwise.comp = ~lvm.clusters.zostera.1, ## check the pairwise comparison between clusters
                                    show.time = "all") 
)
Resampling begins for test 1.
    Resampling run 0 finished. Time elapsed: 0.00 minutes...
    Resampling run 100 finished. Time elapsed: 0.12 minutes...
    Resampling run 200 finished. Time elapsed: 0.25 minutes...
    Resampling run 300 finished. Time elapsed: 0.38 minutes...
    Resampling run 400 finished. Time elapsed: 0.50 minutes...
    Resampling run 500 finished. Time elapsed: 0.63 minutes...
    Resampling run 600 finished. Time elapsed: 0.75 minutes...
    Resampling run 700 finished. Time elapsed: 0.88 minutes...
    Resampling run 800 finished. Time elapsed: 1.01 minutes...
    Resampling run 900 finished. Time elapsed: 1.13 minutes...
Time elapsed: 0 hr 1 min 14 sec
Analysis of Deviance Table

Model: manyglm(formula = zoo.mvabnd.zostera ~ lvm.clusters.zostera.1, 
Model:     family = "negative.binomial")

Multivariate test:
                       Res.Df Df.diff   Dev Pr(>Dev)    
(Intercept)                31                           
lvm.clusters.zostera.1     29       2 703.6    0.001 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Pairwise comparison results: 
                                                     Observed statistic
lvm.clusters.zostera.1:1 vs lvm.clusters.zostera.1:3              370.0
lvm.clusters.zostera.1:2 vs lvm.clusters.zostera.1:3              346.1
lvm.clusters.zostera.1:1 vs lvm.clusters.zostera.1:2              319.4
                                                     Free Stepdown Adjusted P-Value    
lvm.clusters.zostera.1:1 vs lvm.clusters.zostera.1:3                          0.001 ***
lvm.clusters.zostera.1:2 vs lvm.clusters.zostera.1:3                          0.001 ***
lvm.clusters.zostera.1:1 vs lvm.clusters.zostera.1:2                          0.001 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1


Univariate Tests:
                       Abra.alba          Abra.sp.          Actiniaria         
                             Dev Pr(>Dev)      Dev Pr(>Dev)        Dev Pr(>Dev)
(Intercept)                                                                    
lvm.clusters.zostera.1    25.931    0.002    4.159    0.986      1.386    1.000
                       Alitta.succinea          Ampelisca.diadema         
                                   Dev Pr(>Dev)               Dev Pr(>Dev)
(Intercept)                                                               
lvm.clusters.zostera.1           8.646    0.434            20.059    0.005
                       Amphibalanus.improvisus          Ampithoe.sp.         
                                           Dev Pr(>Dev)          Dev Pr(>Dev)
(Intercept)                                                                  
lvm.clusters.zostera.1                  14.882    0.036        6.321    0.802
                       Anadara.kagoshimensis          Apherusa.bispinosa         
                                         Dev Pr(>Dev)                Dev Pr(>Dev)
(Intercept)                                                                      
lvm.clusters.zostera.1                 1.386    1.000              1.962    1.000
                       Apseudopsis.ostroumovi          Bittium.reticulatum         
                                          Dev Pr(>Dev)                 Dev Pr(>Dev)
(Intercept)                                                                        
lvm.clusters.zostera.1                 30.855    0.001              31.183    0.001
                       Brachynotus.sexdentatus          Capitella.capitata         
                                           Dev Pr(>Dev)                Dev Pr(>Dev)
(Intercept)                                                                        
lvm.clusters.zostera.1                   0.575    1.000             26.213    0.002
                       Capitella.minima          Chamelea.gallina         
                                    Dev Pr(>Dev)              Dev Pr(>Dev)
(Intercept)                                                               
lvm.clusters.zostera.1            0.739    1.000            26.23    0.002
                       Chironomidae.larvae          Cumella.limicola         
                                       Dev Pr(>Dev)              Dev Pr(>Dev)
(Intercept)                                                                  
lvm.clusters.zostera.1               4.195    0.979           32.545    0.001
                       Cumella.pygmaea          Cytharella.costulata         
                                   Dev Pr(>Dev)                  Dev Pr(>Dev)
(Intercept)                                                                  
lvm.clusters.zostera.1           4.228    0.979                3.122    0.996
                       Diogenes.pugilator          Eteone.flava          Eunice.vittata
                                      Dev Pr(>Dev)          Dev Pr(>Dev)            Dev
(Intercept)                                                                            
lvm.clusters.zostera.1              0.896    1.000        4.159    0.987          0.871
                                Eurydice.dollfusi          Exogone.naidina         
                       Pr(>Dev)               Dev Pr(>Dev)             Dev Pr(>Dev)
(Intercept)                                                                        
lvm.clusters.zostera.1    1.000             4.228    0.979           5.944    0.839
                       Gastrosaccus.sanctus          Genetyllis.tuberculata         
                                        Dev Pr(>Dev)                    Dev Pr(>Dev)
(Intercept)                                                                         
lvm.clusters.zostera.1                1.962    1.000                  0.467    1.000
                       Glycera.sp.          Glycera.tridactyla         
                               Dev Pr(>Dev)                Dev Pr(>Dev)
(Intercept)                                                            
lvm.clusters.zostera.1       7.992    0.559              4.484    0.961
                       Glycera.unicornis          Harmothoe.imbricata         
                                     Dev Pr(>Dev)                 Dev Pr(>Dev)
(Intercept)                                                                   
lvm.clusters.zostera.1             1.386    1.000               1.841    1.000
                       Harmothoe.reticulata          Heteromastus.filiformis         
                                        Dev Pr(>Dev)                     Dev Pr(>Dev)
(Intercept)                                                                          
lvm.clusters.zostera.1                 5.13    0.925                  10.222    0.247
                       Hirudinea          Hydrobia.acuta          Hydrobia.sp.         
                             Dev Pr(>Dev)            Dev Pr(>Dev)          Dev Pr(>Dev)
(Intercept)                                                                            
lvm.clusters.zostera.1     0.915    1.000          1.438    1.000        1.681    1.000
                       Iphinoe.tenella          Kellia.suborbicularis         
                                   Dev Pr(>Dev)                   Dev Pr(>Dev)
(Intercept)                                                                   
lvm.clusters.zostera.1            4.16    0.981                 4.584    0.949
                       Lagis.koreni          Leiochone.leiopygos         
                                Dev Pr(>Dev)                 Dev Pr(>Dev)
(Intercept)                                                              
lvm.clusters.zostera.1        9.705    0.296               6.218    0.812
                       Lentidium.mediterraneum          Lepidochitona.cinerea         
                                           Dev Pr(>Dev)                   Dev Pr(>Dev)
(Intercept)                                                                           
lvm.clusters.zostera.1                   3.923    0.989                 1.962    1.000
                       Loripes.orbiculatus          Lucinella.divaricata         
                                       Dev Pr(>Dev)                  Dev Pr(>Dev)
(Intercept)                                                                      
lvm.clusters.zostera.1              25.259    0.002                4.257    0.979
                       Magelona.papillicornis          Maldane.glebifex         
                                          Dev Pr(>Dev)              Dev Pr(>Dev)
(Intercept)                                                                     
lvm.clusters.zostera.1                  1.962    1.000            1.386    1.000
                       Melinna.palmata          Microdeutopus.gryllotalpa         
                                   Dev Pr(>Dev)                       Dev Pr(>Dev)
(Intercept)                                                                       
lvm.clusters.zostera.1          24.203    0.003                     3.088    0.996
                       Micromaldane.ornithochaeta          Micronephthys.stammeri
                                              Dev Pr(>Dev)                    Dev
(Intercept)                                                                      
lvm.clusters.zostera.1                      4.544    0.959                  0.575
                                Microphthalmus.fragilis          Microphthalmus.sp.
                       Pr(>Dev)                     Dev Pr(>Dev)                Dev
(Intercept)                                                                        
lvm.clusters.zostera.1    1.000                   1.437    1.000              9.396
                                Monocorophium.acherusicum          Mytilaster.lineatus
                       Pr(>Dev)                       Dev Pr(>Dev)                 Dev
(Intercept)                                                                           
lvm.clusters.zostera.1    0.342                    38.329    0.001              21.933
                                Mytilus.galloprovincialis          Nemertea         
                       Pr(>Dev)                       Dev Pr(>Dev)      Dev Pr(>Dev)
(Intercept)                                                                         
lvm.clusters.zostera.1    0.003                     1.386    1.000    3.554    0.995
                       Nephtys.cirrosa          Nephtys.kersivalensis         
                                   Dev Pr(>Dev)                   Dev Pr(>Dev)
(Intercept)                                                                   
lvm.clusters.zostera.1           0.575    1.000                 1.386    1.000
                       Nereis.perivisceralis          Nereis.pulsatoria         
                                         Dev Pr(>Dev)               Dev Pr(>Dev)
(Intercept)                                                                     
lvm.clusters.zostera.1                 1.962    1.000             2.987    0.998
                       Nototropis.guttatus          Oligochaeta         
                                       Dev Pr(>Dev)         Dev Pr(>Dev)
(Intercept)                                                             
lvm.clusters.zostera.1                2.61    0.999      21.776    0.003
                       Paradoneis.harpagonea          Parthenina.interstincta         
                                         Dev Pr(>Dev)                     Dev Pr(>Dev)
(Intercept)                                                                           
lvm.clusters.zostera.1                 1.386    1.000                   1.965    1.000
                       Parvicardium.exiguum          Perinereis.cultrifera         
                                        Dev Pr(>Dev)                   Dev Pr(>Dev)
(Intercept)                                                                        
lvm.clusters.zostera.1                2.086    1.000                  3.68    0.995
                       Perioculodes.longimanus          Phoronida         
                                           Dev Pr(>Dev)       Dev Pr(>Dev)
(Intercept)                                                               
lvm.clusters.zostera.1                   2.254    0.999     4.088    0.989
                       Phyllodoce.sp.          Platyhelminthes         
                                  Dev Pr(>Dev)             Dev Pr(>Dev)
(Intercept)                                                            
lvm.clusters.zostera.1          4.159    0.987           4.534    0.959
                       Platynereis.dumerilii          Polititapes.aureus         
                                         Dev Pr(>Dev)                Dev Pr(>Dev)
(Intercept)                                                                      
lvm.clusters.zostera.1                  7.28    0.627              3.315    0.996
                       Polychaeta.larvae          Polydora.ciliata         
                                     Dev Pr(>Dev)              Dev Pr(>Dev)
(Intercept)                                                                
lvm.clusters.zostera.1             4.159    0.984            15.69    0.022
                       Polygordius.neapolitanus          Prionospio.cirrifera         
                                            Dev Pr(>Dev)                  Dev Pr(>Dev)
(Intercept)                                                                           
lvm.clusters.zostera.1                    4.159    0.984               13.193    0.072
                       Protodorvillea.kefersteini          Pseudocuma.longicorne
                                              Dev Pr(>Dev)                   Dev
(Intercept)                                                                     
lvm.clusters.zostera.1                     17.536    0.009                 1.491
                                Rissoa.membranacea          Rissoa.splendida         
                       Pr(>Dev)                Dev Pr(>Dev)              Dev Pr(>Dev)
(Intercept)                                                                          
lvm.clusters.zostera.1    1.000              0.158    1.000           11.549    0.145
                       Salvatoria.clavata          Schistomeringos.rudolphi         
                                      Dev Pr(>Dev)                      Dev Pr(>Dev)
(Intercept)                                                                         
lvm.clusters.zostera.1             17.003    0.015                    2.634    0.999
                       Sphaerosyllis.hystrix          Spio.filicornis         
                                         Dev Pr(>Dev)             Dev Pr(>Dev)
(Intercept)                                                                   
lvm.clusters.zostera.1                12.713    0.085          28.109    0.001
                       Spisula.subtruncata          Stenosoma.capito         
                                       Dev Pr(>Dev)              Dev Pr(>Dev)
(Intercept)                                                                  
lvm.clusters.zostera.1               5.885    0.842            5.011    0.930
                       Syllis.gracilis          Syllis.hyalina          Tellina.tenuis
                                   Dev Pr(>Dev)            Dev Pr(>Dev)            Dev
(Intercept)                                                                           
lvm.clusters.zostera.1           5.956    0.839          2.048    1.000          1.491
                                Thracia.phaseolina          Tricolia.pullus         
                       Pr(>Dev)                Dev Pr(>Dev)             Dev Pr(>Dev)
(Intercept)                                                                         
lvm.clusters.zostera.1    1.000              1.962    1.000           7.956    0.559
                       Tritia.neritea          Tritia.reticulata          Turbellaria
                                  Dev Pr(>Dev)               Dev Pr(>Dev)         Dev
(Intercept)                                                                          
lvm.clusters.zostera.1          1.406    1.000             2.932    0.999       0.135
                                Upogebia.pusilla         
                       Pr(>Dev)              Dev Pr(>Dev)
(Intercept)                                              
lvm.clusters.zostera.1    1.000            4.257    0.979
Arguments:
 Test statistics calculated assuming uncorrelated response (for faster computation) 
P-value calculated using 999 resampling iterations via PIT-trap resampling (to account for correlation in testing.

Aaaand the differences between clusters are highly significant in this iteration..

Save the ANOVA, too.

write_rds(glms.lvm.zostera.1.aov, 
          here(save.dir, "glms_lvm_zostera_1_anova.RDS"))

NOW let’s get the taxa with the highest contributions to the tested pattern.

## get the top contributing species for the initial zostera GLMs 
(top.sp.glms.lvm.zostera.1 <- top_n_sp_glm(glms.lvm.zostera.1.aov, tot.dev.expl = 0.75)
)
[1] "Total deviance explained: 0.76"
 Monocorophium.acherusicum           Cumella.limicola        Bittium.reticulatum 
                 38.328670                  32.545296                  31.182981 
    Apseudopsis.ostroumovi            Spio.filicornis           Chamelea.gallina 
                 30.854772                  28.108956                  26.230014 
        Capitella.capitata                  Abra.alba        Loripes.orbiculatus 
                 26.212753                  25.931365                  25.258931 
           Melinna.palmata        Mytilaster.lineatus                Oligochaeta 
                 24.202974                  21.932810                  21.776133 
         Ampelisca.diadema Protodorvillea.kefersteini         Salvatoria.clavata 
                 20.058951                  17.536359                  17.003452 
          Polydora.ciliata    Amphibalanus.improvisus       Prionospio.cirrifera 
                 15.689516                  14.882244                  13.192537 
     Sphaerosyllis.hystrix           Rissoa.splendida    Heteromastus.filiformis 
                 12.713470                  11.548802                  10.221754 
              Lagis.koreni         Microphthalmus.sp.            Alitta.succinea 
                  9.704792                   9.395618                   8.646146 
               Glycera.sp.            Tricolia.pullus      Platynereis.dumerilii 
                  7.992056                   7.955930                   7.279560 
              Ampithoe.sp.        Leiochone.leiopygos            Syllis.gracilis 
                  6.321173                   6.218039                   5.956444 
## unfortunately, mvabund likes to rename my species when converting the data to matrix (no spaces in names), and since I'm going to look them up in my initial untransformed count data, I have to change them back..   
names(top.sp.glms.lvm.zostera.1) <- names(top.sp.glms.lvm.zostera.1) %>% 
  str_replace(pattern = "\\.", replacement = " ")
top.sp.glms.lvm.zostera.1
 Monocorophium acherusicum           Cumella limicola        Bittium reticulatum 
                 38.328670                  32.545296                  31.182981 
    Apseudopsis ostroumovi            Spio filicornis           Chamelea gallina 
                 30.854772                  28.108956                  26.230014 
        Capitella capitata                  Abra alba        Loripes orbiculatus 
                 26.212753                  25.931365                  25.258931 
           Melinna palmata        Mytilaster lineatus                Oligochaeta 
                 24.202974                  21.932810                  21.776133 
         Ampelisca diadema Protodorvillea kefersteini         Salvatoria clavata 
                 20.058951                  17.536359                  17.003452 
          Polydora ciliata    Amphibalanus improvisus       Prionospio cirrifera 
                 15.689516                  14.882244                  13.192537 
     Sphaerosyllis hystrix           Rissoa splendida    Heteromastus filiformis 
                 12.713470                  11.548802                  10.221754 
              Lagis koreni         Microphthalmus sp.            Alitta succinea 
                  9.704792                   9.395618                   8.646146 
               Glycera sp.            Tricolia pullus      Platynereis dumerilii 
                  7.992056                   7.955930                   7.279560 
              Ampithoe sp.        Leiochone leiopygos            Syllis gracilis 
                  6.321173                   6.218039                   5.956444 

Try to plot these top contributing species - for whatever that’s worth, because 50 species on a plot is still a monstrosity.

## get the species and their abundances from the original count data, and transform them to long format
(abnd.top.sp.glms.lvm.zostera.1 <- zoo.abnd.zostera %>% 
   select(station, names(top.sp.glms.lvm.zostera.1)) %>% 
   gather(key = "species", value = "count", -station) %>% 
   ## turn species into a factor, or you'll be very very sorry later, when they're out of order on the plot. NB need to be in REVERSE order, because ggplot plots from bottom to top, and I want the top-contributing species on top. 
   mutate(species = factor(species, levels = rev(names(top.sp.glms.lvm.zostera.1)))) %>% 
   mutate(group = factor(case_when(station %in% c("Poda", "Otmanli") ~ 1, 
                                   station == "Vromos" ~ 2, 
                                   station %in% c("Gradina", "Ropotamo") ~ 3))) ## add the groups to the long df 
)
(plot.top.sp.glms.lvm.zostera.1 <- plot_top_n(abnd.top.sp.glms.lvm.zostera.1,
                                         mapping = aes(x = species, y = log_y_min(count), colour = group),
                                         labs.legend = paste0("group", as.character(levels(abnd.top.sp.glms.lvm.zostera.1$group))),
                                         lab.y = "Abundance (log(y/min + 1))",
                                         palette = "Set2"
                                        ) +
    theme(legend.position = "top", legend.title = element_blank())
)

Well this is a nightmarish plot, but more tolerable than the one for the sand stations - there are less species here, so at least it’s readable..

Extract the top-contributing species to each cluster (this same nightmare above, but as a table). This chunk is STILL hopelessly ugly and clumsy.

top.sp.abnd.glms.lvm.zostera.1 <- lapply(names(glms.lvm.zostera.1.summary$aliased), function(x) top_sp_glms_table(glms.lvm.zostera.1.summary, x, p = 0.05)) 
## fix species names (remove dot) 
top.sp.abnd.glms.lvm.zostera.1 <- lapply(top.sp.abnd.glms.lvm.zostera.1, function(x) x %>% mutate(species = str_replace(species, pattern = "\\.", replacement = " ")))
## rename columns (= group names) - right now they are something like "lvm.clusters.zostera2" etc.
top.sp.abnd.glms.lvm.zostera.1 <- lapply(top.sp.abnd.glms.lvm.zostera.1, function(x) x %>% rename_at(vars(contains("lvm.clusters.zostera.1")), list(~str_replace_all(., pattern = "lvm.clusters.zostera.1", "group_"))))
top.sp.abnd.glms.lvm.zostera.1 <- lapply(top.sp.abnd.glms.lvm.zostera.1, function(x) x %>% rename_at(vars(contains("Intercept")), list(~str_replace_all(., pattern = "\\(Intercept\\)", "group_1"))))
## pull the abundances from the original count df and add to the summary glm tables 
## make a long df of abundances & add clusters  
zoo.abnd.zostera.long.1 <- zoo.abnd.zostera %>%
  select(-c(month:replicate)) %>%
  gather(key = "species", value = "count", -station) %>% 
  mutate(group = case_when(station %in% c("Poda", "Otmanli") ~ 1, 
                           station == "Vromos" ~ 2, 
                           station %in% c("Gradina", "Ropotamo") ~ 3)
         )
## sum sp abundances by group; nest by group
zoo.abnd.zostera.long.1.smry <- zoo.abnd.zostera.long.1 %>% 
  group_by(species, group) %>% 
  summarise(total_count = sum(count)) %>% 
  group_by(group) %>%
  nest()
## add the counts to the group dfs - wow that's an ugly, ugly hack. Wish I had more time to write this up properly.. 
top.sp.abnd.glms.lvm.zostera.1 <- map2(top.sp.abnd.glms.lvm.zostera.1, zoo.abnd.zostera.long.1.smry %>% pull(group), ~left_join(.x, zoo.abnd.zostera.long.1.smry %>% filter(group == .y) %>% unnest(), by = "species"))
## since these are sum counts over all the replicates (that's why the monstrous numbers), average them to be mean counts per group. NB different groups consist of different numbers of replicates, b.c. some groups consist of more than one station
(top.sp.abnd.glms.lvm.zostera.1 <- map2(top.sp.abnd.glms.lvm.zostera.1, c(16, 4, 12), function(x, y) x %>% mutate(mean_count = total_count/y))
)
[[1]]

[[2]]

[[3]]
NA

In this case, the model shows which species exhibit a reaction based on the chosen groups - in other words, which species are more likely to be more/less abundant in each group.
I have to say, in the case of the seagrasses and case 1 clusters, there are much fewer species that exhibit a significant response - around 10 for each group.
The LRs are lower for groups 2 and 3 - not sure if this means anything, but for group 1 they are much much higher..
For group 1 (= Z1-Z2), the species/taxa with significantly higher abundance are: Bittium reticulatum, Capitella minima, Oligochaeta, H. filiformis, Polydora ciliata, Prionospio cirrifera, R. membranacea, A. alba, A.diadema, M. acherusicum; and the only one with a significantly lower abundance - Chamelea gallina.
For group 2 (= Z3), the species with higher abundance are: M. acherusicum, S. filicornis, A.dadema. The species with lower abundance are: B. reticulatum, A. alba, Oligochaeta, S. clavata, P. ciliata, P. cirrifera, H. filiformis.
For group 3 (= Z4-Z5), the species with higher abundance are: Cumella limicola, Apseudopsis ostroumovi, Capitella capitata, Mytilaster lineatus, Loripes orbiculatus; less so, but still present - C. gallina, S. clavata. The species with lower abundance are: Abra alba, Melinna palmata (totally absent).

I’ll test each station as its own group, too (as I did before, with the classical multivariate methods) - I’m not sure how much I can trust this grouping (in particular group 3 is a bit far-fetched, if you ask me..).

LVM clusters - case 2 Check the model assumptions.

plot(manyglm(zoo.mvabnd.zostera ~ lvm.clusters.zostera.2, family = "negative.binomial"))

meanvar.plot(zoo.mvabnd.zostera ~ lvm.clusters.zostera.2, table = TRUE)

It’s not perfect, but it’s not too terrible either. I think it’s a little worse than the case 1 fit.

  1. Assumed relationship between mean abundance and environmental variables - link function and formula.

Everything looks more or less fine; fit the model.

glms.lvm.zostera.2 <- manyglm(zoo.mvabnd.zostera ~ lvm.clusters.zostera.2, 
                              family = "negative.binomial")

Explore the fit (residuals, diagnostic plots, etc.).

## residuals vs fitted values
plot(glms.lvm.zostera.2)

## all traditional (g)lm diagnostic plots
plot.manyglm(glms.lvm.zostera.2, which = 1:3)

# ### source mvabund GLM plotting functions modified to use a grey palette - I just can't redo these plots on my own, the function is doing too complicated things internally to scale the x and y axes
# source(here(functions.dir, "default.plot.manyglm_grey.R"))
# source(here(functions.dir, "plot.manyglm_grey.R"))
# 
# par(mfrow = c(2,2))
# lapply(2:3, function(i) plot.manyglm.grey(glms.lvm.zostera, which = i, sub.caption = ""))
# par(mfrow = c(2, 2))

Save the model!

write_rds(glms.lvm.zostera.2, 
          here(save.dir, "glms_lvm_zostera_2.RDS"))

Let’s see the model summary (NB takes a LOT of time if there are many resamplings!).

(glms.lvm.zostera.2.summary <- summary(glms.lvm.zostera.2, 
                                       test = "LR", p.uni = "adjusted",
                                       nBoot = 999, ## limit the number of permutations if you just want to check it out
                                       show.time = "all")
)

The factor is highly significant according to the models.

Again, save the summary for safekeeping, but also run an anova.

write_rds(glms.lvm.zostera.2.summary, 
          here(save.dir, "glms_lvm_zostera_2_summary.RDS"))

Run the anova on the model.

(glms.lvm.zostera.2.aov <- anova.manyglm(glms.lvm.zostera.2, 
                                         test = "LR", p.uni = "adjusted", 
                                         nBoot = 999, ## limit the number of permutations for a shorter run time   
                                         pairwise.comp = ~lvm.clusters.zostera.2, ## check the pairwise comparison between clusters
                                         show.time = "all") 
)
Resampling begins for test 1.
    Resampling run 0 finished. Time elapsed: 0.00 minutes...
    Resampling run 100 finished. Time elapsed: 0.12 minutes...
    Resampling run 200 finished. Time elapsed: 0.24 minutes...
    Resampling run 300 finished. Time elapsed: 0.37 minutes...
    Resampling run 400 finished. Time elapsed: 0.48 minutes...
    Resampling run 500 finished. Time elapsed: 0.60 minutes...
    Resampling run 600 finished. Time elapsed: 0.72 minutes...
    Resampling run 700 finished. Time elapsed: 0.84 minutes...
    Resampling run 800 finished. Time elapsed: 0.96 minutes...
    Resampling run 900 finished. Time elapsed: 1.08 minutes...
Time elapsed: 0 hr 1 min 12 sec
Analysis of Deviance Table

Model: manyglm(formula = zoo.mvabnd.zostera ~ lvm.clusters.zostera.2, 
Model:     family = "negative.binomial")

Multivariate test:
                       Res.Df Df.diff  Dev Pr(>Dev)    
(Intercept)                31                          
lvm.clusters.zostera.2     27       4 1223    0.001 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Pairwise comparison results: 
                                                     Observed statistic
lvm.clusters.zostera.2:1 vs lvm.clusters.zostera.2:4              418.6
lvm.clusters.zostera.2:3 vs lvm.clusters.zostera.2:4              368.1
lvm.clusters.zostera.2:3 vs lvm.clusters.zostera.2:5              336.6
lvm.clusters.zostera.2:2 vs lvm.clusters.zostera.2:3              325.3
lvm.clusters.zostera.2:1 vs lvm.clusters.zostera.2:5              310.4
lvm.clusters.zostera.2:4 vs lvm.clusters.zostera.2:5              295.1
lvm.clusters.zostera.2:2 vs lvm.clusters.zostera.2:4              278.8
lvm.clusters.zostera.2:1 vs lvm.clusters.zostera.2:3              278.8
lvm.clusters.zostera.2:2 vs lvm.clusters.zostera.2:5              271.7
lvm.clusters.zostera.2:1 vs lvm.clusters.zostera.2:2              219.8
                                                     Free Stepdown Adjusted P-Value   
lvm.clusters.zostera.2:1 vs lvm.clusters.zostera.2:4                          0.002 **
lvm.clusters.zostera.2:3 vs lvm.clusters.zostera.2:4                          0.008 **
lvm.clusters.zostera.2:3 vs lvm.clusters.zostera.2:5                          0.009 **
lvm.clusters.zostera.2:2 vs lvm.clusters.zostera.2:3                          0.009 **
lvm.clusters.zostera.2:1 vs lvm.clusters.zostera.2:5                          0.009 **
lvm.clusters.zostera.2:4 vs lvm.clusters.zostera.2:5                          0.009 **
lvm.clusters.zostera.2:2 vs lvm.clusters.zostera.2:4                          0.009 **
lvm.clusters.zostera.2:1 vs lvm.clusters.zostera.2:3                          0.009 **
lvm.clusters.zostera.2:2 vs lvm.clusters.zostera.2:5                          0.009 **
lvm.clusters.zostera.2:1 vs lvm.clusters.zostera.2:2                          0.009 **
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1


Univariate Tests:
                       Abra.alba          Abra.sp.          Actiniaria         
                             Dev Pr(>Dev)      Dev Pr(>Dev)        Dev Pr(>Dev)
(Intercept)                                                                    
lvm.clusters.zostera.2    27.461    0.002    4.159    1.000      2.773    1.000
                       Alitta.succinea          Ampelisca.diadema         
                                   Dev Pr(>Dev)               Dev Pr(>Dev)
(Intercept)                                                               
lvm.clusters.zostera.2          36.585    0.001             30.57    0.001
                       Amphibalanus.improvisus          Ampithoe.sp.         
                                           Dev Pr(>Dev)          Dev Pr(>Dev)
(Intercept)                                                                  
lvm.clusters.zostera.2                  23.408    0.009       12.209    0.448
                       Anadara.kagoshimensis          Apherusa.bispinosa         
                                         Dev Pr(>Dev)                Dev Pr(>Dev)
(Intercept)                                                                      
lvm.clusters.zostera.2                 2.773    1.000              2.773    1.000
                       Apseudopsis.ostroumovi          Bittium.reticulatum         
                                          Dev Pr(>Dev)                 Dev Pr(>Dev)
(Intercept)                                                                        
lvm.clusters.zostera.2                 52.794    0.001              34.193    0.001
                       Brachynotus.sexdentatus          Capitella.capitata         
                                           Dev Pr(>Dev)                Dev Pr(>Dev)
(Intercept)                                                                        
lvm.clusters.zostera.2                   2.773    1.000             33.199    0.001
                       Capitella.minima          Chamelea.gallina         
                                    Dev Pr(>Dev)              Dev Pr(>Dev)
(Intercept)                                                               
lvm.clusters.zostera.2            7.227    0.941           28.525    0.001
                       Chironomidae.larvae          Cumella.limicola         
                                       Dev Pr(>Dev)              Dev Pr(>Dev)
(Intercept)                                                                  
lvm.clusters.zostera.2               9.651    0.761           41.328    0.001
                       Cumella.pygmaea          Cytharella.costulata         
                                   Dev Pr(>Dev)                  Dev Pr(>Dev)
(Intercept)                                                                  
lvm.clusters.zostera.2           6.118    0.976                7.354    0.936
                       Diogenes.pugilator          Eteone.flava          Eunice.vittata
                                      Dev Pr(>Dev)          Dev Pr(>Dev)            Dev
(Intercept)                                                                            
lvm.clusters.zostera.2              3.059    1.000        4.159    1.000          3.779
                                Eurydice.dollfusi          Exogone.naidina         
                       Pr(>Dev)               Dev Pr(>Dev)             Dev Pr(>Dev)
(Intercept)                                                                        
lvm.clusters.zostera.2    1.000             6.118    0.976           8.477    0.879
                       Gastrosaccus.sanctus          Genetyllis.tuberculata         
                                        Dev Pr(>Dev)                    Dev Pr(>Dev)
(Intercept)                                                                         
lvm.clusters.zostera.2                2.773    1.000                  7.712    0.926
                       Glycera.sp.          Glycera.tridactyla         
                               Dev Pr(>Dev)                Dev Pr(>Dev)
(Intercept)                                                            
lvm.clusters.zostera.2       7.992    0.918              5.516    0.994
                       Glycera.unicornis          Harmothoe.imbricata         
                                     Dev Pr(>Dev)                 Dev Pr(>Dev)
(Intercept)                                                                   
lvm.clusters.zostera.2             2.773    1.000               8.753    0.861
                       Harmothoe.reticulata          Heteromastus.filiformis         
                                        Dev Pr(>Dev)                     Dev Pr(>Dev)
(Intercept)                                                                          
lvm.clusters.zostera.2                15.21    0.180                  28.142    0.001
                       Hirudinea          Hydrobia.acuta          Hydrobia.sp.         
                             Dev Pr(>Dev)            Dev Pr(>Dev)          Dev Pr(>Dev)
(Intercept)                                                                            
lvm.clusters.zostera.2     1.726    1.000          2.932    1.000        5.959    0.980
                       Iphinoe.tenella          Kellia.suborbicularis         
                                   Dev Pr(>Dev)                   Dev Pr(>Dev)
(Intercept)                                                                   
lvm.clusters.zostera.2           9.824    0.747                 9.077    0.846
                       Lagis.koreni          Leiochone.leiopygos         
                                Dev Pr(>Dev)                 Dev Pr(>Dev)
(Intercept)                                                              
lvm.clusters.zostera.2       16.471    0.131              15.331    0.179
                       Lentidium.mediterraneum          Lepidochitona.cinerea         
                                           Dev Pr(>Dev)                   Dev Pr(>Dev)
(Intercept)                                                                           
lvm.clusters.zostera.2                   5.545    0.990                 2.773    1.000
                       Loripes.orbiculatus          Lucinella.divaricata         
                                       Dev Pr(>Dev)                  Dev Pr(>Dev)
(Intercept)                                                                      
lvm.clusters.zostera.2              31.348    0.001                6.172    0.974
                       Magelona.papillicornis          Maldane.glebifex         
                                          Dev Pr(>Dev)              Dev Pr(>Dev)
(Intercept)                                                                     
lvm.clusters.zostera.2                  2.773    1.000            2.773    1.000
                       Melinna.palmata          Microdeutopus.gryllotalpa         
                                   Dev Pr(>Dev)                       Dev Pr(>Dev)
(Intercept)                                                                       
lvm.clusters.zostera.2           26.86    0.002                     16.35    0.131
                       Micromaldane.ornithochaeta          Micronephthys.stammeri
                                              Dev Pr(>Dev)                    Dev
(Intercept)                                                                      
lvm.clusters.zostera.2                      6.655    0.962                  4.159
                                Microphthalmus.fragilis          Microphthalmus.sp.
                       Pr(>Dev)                     Dev Pr(>Dev)                Dev
(Intercept)                                                                        
lvm.clusters.zostera.2    0.999                   2.931    1.000             11.855
                                Monocorophium.acherusicum          Mytilaster.lineatus
                       Pr(>Dev)                       Dev Pr(>Dev)                 Dev
(Intercept)                                                                           
lvm.clusters.zostera.2    0.487                    39.891    0.001              47.863
                                Mytilus.galloprovincialis          Nemertea         
                       Pr(>Dev)                       Dev Pr(>Dev)      Dev Pr(>Dev)
(Intercept)                                                                         
lvm.clusters.zostera.2    0.001                     2.773    1.000   10.046    0.723
                       Nephtys.cirrosa          Nephtys.kersivalensis         
                                   Dev Pr(>Dev)                   Dev Pr(>Dev)
(Intercept)                                                                   
lvm.clusters.zostera.2           2.773    1.000                 2.773    1.000
                       Nereis.perivisceralis          Nereis.pulsatoria         
                                         Dev Pr(>Dev)               Dev Pr(>Dev)
(Intercept)                                                                     
lvm.clusters.zostera.2                 2.773    1.000             6.238    0.971
                       Nototropis.guttatus          Oligochaeta         
                                       Dev Pr(>Dev)         Dev Pr(>Dev)
(Intercept)                                                             
lvm.clusters.zostera.2                7.21    0.941      36.765    0.001
                       Paradoneis.harpagonea          Parthenina.interstincta         
                                         Dev Pr(>Dev)                     Dev Pr(>Dev)
(Intercept)                                                                           
lvm.clusters.zostera.2                 2.773    1.000                   4.546    0.997
                       Parvicardium.exiguum          Perinereis.cultrifera         
                                        Dev Pr(>Dev)                   Dev Pr(>Dev)
(Intercept)                                                                        
lvm.clusters.zostera.2                2.973    1.000                 6.689    0.962
                       Perioculodes.longimanus          Phoronida         
                                           Dev Pr(>Dev)       Dev Pr(>Dev)
(Intercept)                                                               
lvm.clusters.zostera.2                   4.365    0.999     5.483    0.994
                       Phyllodoce.sp.          Platyhelminthes         
                                  Dev Pr(>Dev)             Dev Pr(>Dev)
(Intercept)                                                            
lvm.clusters.zostera.2          4.159    1.000           8.508    0.879
                       Platynereis.dumerilii          Polititapes.aureus         
                                         Dev Pr(>Dev)                Dev Pr(>Dev)
(Intercept)                                                                      
lvm.clusters.zostera.2                  8.91    0.851             10.998    0.575
                       Polychaeta.larvae          Polydora.ciliata         
                                     Dev Pr(>Dev)              Dev Pr(>Dev)
(Intercept)                                                                
lvm.clusters.zostera.2             4.159    0.999           41.905    0.001
                       Polygordius.neapolitanus          Prionospio.cirrifera         
                                            Dev Pr(>Dev)                  Dev Pr(>Dev)
(Intercept)                                                                           
lvm.clusters.zostera.2                    4.159    0.999               46.273    0.001
                       Protodorvillea.kefersteini          Pseudocuma.longicorne
                                              Dev Pr(>Dev)                   Dev
(Intercept)                                  <NA>     <NA>                  <NA>
lvm.clusters.zostera.2                      30.14    0.001                 3.112
                                Rissoa.membranacea          Rissoa.splendida         
                       Pr(>Dev)                Dev Pr(>Dev)              Dev Pr(>Dev)
(Intercept)                <NA>               <NA>     <NA>             <NA>     <NA>
lvm.clusters.zostera.2    1.000               2.72    1.000           17.118    0.113
                       Salvatoria.clavata          Schistomeringos.rudolphi         
                                      Dev Pr(>Dev)                      Dev Pr(>Dev)
(Intercept)                          <NA>     <NA>                     <NA>     <NA>
lvm.clusters.zostera.2             32.959    0.001                   13.822    0.291
                       Sphaerosyllis.hystrix          Spio.filicornis         
                                         Dev Pr(>Dev)             Dev Pr(>Dev)
(Intercept)                             <NA>     <NA>            <NA>     <NA>
lvm.clusters.zostera.2                 16.76    0.124          34.879    0.001
                       Spisula.subtruncata          Stenosoma.capito         
                                       Dev Pr(>Dev)              Dev Pr(>Dev)
(Intercept)                           <NA>     <NA>             <NA>     <NA>
lvm.clusters.zostera.2               5.885    0.980            13.85    0.291
                       Syllis.gracilis          Syllis.hyalina          Tellina.tenuis
                                   Dev Pr(>Dev)            Dev Pr(>Dev)            Dev
(Intercept)                       <NA>     <NA>           <NA>     <NA>           <NA>
lvm.clusters.zostera.2          28.543    0.001          4.555    0.997          4.499
                                Thracia.phaseolina          Tricolia.pullus         
                       Pr(>Dev)                Dev Pr(>Dev)             Dev Pr(>Dev)
(Intercept)                <NA>               <NA>     <NA>            <NA>     <NA>
lvm.clusters.zostera.2    0.997              2.773    1.000          14.668    0.223
                       Tritia.neritea          Tritia.reticulata          Turbellaria
                                  Dev Pr(>Dev)               Dev Pr(>Dev)         Dev
(Intercept)                      <NA>     <NA>              <NA>     <NA>        <NA>
lvm.clusters.zostera.2          5.516    0.994            11.233    0.558       2.652
                                Upogebia.pusilla         
                       Pr(>Dev)              Dev Pr(>Dev)
(Intercept)                <NA>             <NA>     <NA>
lvm.clusters.zostera.2    1.000           10.026    0.723
Arguments:
 Test statistics calculated assuming uncorrelated response (for faster computation) 
P-value calculated using 999 resampling iterations via PIT-trap resampling (to account for correlation in testing.

Again, these groups are sufficiently different from one another.. No clue here.

Save the ANOVA, too.

write_rds(glms.lvm.zostera.2.aov, 
          here(save.dir, "glms_lvm_zostera_2_anova.RDS"))

NOW let’s get the taxa with the highest contributions to the tested pattern.

## get the top contributing species for the initial zostera GLMs 
(top.sp.glms.lvm.zostera.2 <- top_n_sp_glm(glms.lvm.zostera.2.aov, tot.dev.expl = 0.75)
)
[1] "Total deviance explained: 0.799"
    Apseudopsis.ostroumovi        Mytilaster.lineatus       Prionospio.cirrifera 
                 52.793744                  47.863335                  46.272692 
          Polydora.ciliata           Cumella.limicola  Monocorophium.acherusicum 
                 41.905219                  41.327723                  39.891356 
               Oligochaeta            Alitta.succinea            Spio.filicornis 
                 36.764590                  36.584687                  34.878811 
       Bittium.reticulatum         Capitella.capitata         Salvatoria.clavata 
                 34.192799                  33.198554                  32.958829 
       Loripes.orbiculatus          Ampelisca.diadema Protodorvillea.kefersteini 
                 31.347733                  30.569510                  30.139960 
           Syllis.gracilis           Chamelea.gallina    Heteromastus.filiformis 
                 28.542915                  28.524575                  28.142266 
                 Abra.alba            Melinna.palmata    Amphibalanus.improvisus 
                 27.461185                  26.859546                  23.408099 
          Rissoa.splendida      Sphaerosyllis.hystrix               Lagis.koreni 
                 17.117581                  16.760313                  16.471224 
 Microdeutopus.gryllotalpa        Leiochone.leiopygos       Harmothoe.reticulata 
                 16.349670                  15.331303                  15.209809 
           Tricolia.pullus           Stenosoma.capito   Schistomeringos.rudolphi 
                 14.667741                  13.849706                  13.822279 
              Ampithoe.sp.         Microphthalmus.sp.          Tritia.reticulata 
                 12.208710                  11.854688                  11.232600 
        Polititapes.aureus                   Nemertea           Upogebia.pusilla 
                 10.998455                  10.045834                  10.025894 
           Iphinoe.tenella        Chironomidae.larvae      Kellia.suborbicularis 
                  9.824385                   9.650905                   9.077281 
     Platynereis.dumerilii 
                  8.910425 
## unfortunately, mvabund likes to rename my species when converting the data to matrix (no spaces in names), and since I'm going to look them up in my initial untransformed count data, I have to change them back..   
names(top.sp.glms.lvm.zostera.2) <- names(top.sp.glms.lvm.zostera.2) %>% 
  str_replace(pattern = "\\.", replacement = " ")
top.sp.glms.lvm.zostera.2
    Apseudopsis ostroumovi        Mytilaster lineatus       Prionospio cirrifera 
                 52.793744                  47.863335                  46.272692 
          Polydora ciliata           Cumella limicola  Monocorophium acherusicum 
                 41.905219                  41.327723                  39.891356 
               Oligochaeta            Alitta succinea            Spio filicornis 
                 36.764590                  36.584687                  34.878811 
       Bittium reticulatum         Capitella capitata         Salvatoria clavata 
                 34.192799                  33.198554                  32.958829 
       Loripes orbiculatus          Ampelisca diadema Protodorvillea kefersteini 
                 31.347733                  30.569510                  30.139960 
           Syllis gracilis           Chamelea gallina    Heteromastus filiformis 
                 28.542915                  28.524575                  28.142266 
                 Abra alba            Melinna palmata    Amphibalanus improvisus 
                 27.461185                  26.859546                  23.408099 
          Rissoa splendida      Sphaerosyllis hystrix               Lagis koreni 
                 17.117581                  16.760313                  16.471224 
 Microdeutopus gryllotalpa        Leiochone leiopygos       Harmothoe reticulata 
                 16.349670                  15.331303                  15.209809 
           Tricolia pullus           Stenosoma capito   Schistomeringos rudolphi 
                 14.667741                  13.849706                  13.822279 
              Ampithoe sp.         Microphthalmus sp.          Tritia reticulata 
                 12.208710                  11.854688                  11.232600 
        Polititapes aureus                   Nemertea           Upogebia pusilla 
                 10.998455                  10.045834                  10.025894 
           Iphinoe tenella        Chironomidae larvae      Kellia suborbicularis 
                  9.824385                   9.650905                   9.077281 
     Platynereis dumerilii 
                  8.910425 

Try to plot these top contributing species - for whatever that’s worth, because 50 species on a plot is still a monstrosity.

## get the species and their abundances from the original count data, and transform them to long format
(abnd.top.sp.glms.lvm.zostera.2 <- zoo.abnd.zostera %>% 
   select(station, names(top.sp.glms.lvm.zostera.2)) %>% 
   gather(key = "species", value = "count", -station) %>% 
   ## turn species into a factor, or you'll be very very sorry later, when they're out of order on the plot. NB need to be in REVERSE order, because ggplot plots from bottom to top, and I want the top-contributing species on top. 
   mutate(species = factor(species, levels = rev(names(top.sp.glms.lvm.zostera.2)))) %>% 
   mutate(group = factor(case_when(station == "Poda" ~ 1,
                                   station == "Otmanli" ~ 2,
                                   station == "Vromos" ~ 3, 
                                   station == "Gradina" ~ 4, 
                                   station == "Ropotamo" ~ 5)))
)
(plot.top.sp.glms.lvm.zostera.2 <- plot_top_n(abnd.top.sp.glms.lvm.zostera.2,
                                              mapping = aes(x = species, y = log_y_min(count), colour = group),
                                              labs.legend = paste0("group", as.character(levels(abnd.top.sp.glms.lvm.zostera.2$group))),
                                              lab.y = "Abundance (log(y/min + 1))",
                                              palette = "Set2"
                                        ) +
    theme(legend.position = "top", legend.title = element_blank())
)

Extract the top-contributing species to each cluster (this same nightmare above, but as a table). This chunk is STILL hopelessly ugly and clumsy.

top.sp.abnd.glms.lvm.zostera.2 <- lapply(names(glms.lvm.zostera.2.summary$aliased), function(x) top_sp_glms_table(glms.lvm.zostera.2.summary, x, p = 0.05)) 
## fix species names (remove dot) 
top.sp.abnd.glms.lvm.zostera.2 <- lapply(top.sp.abnd.glms.lvm.zostera.2, function(x) x %>% mutate(species = str_replace(species, pattern = "\\.", replacement = " ")))
## rename columns (= group names) - right now they are something like "lvm.clusters.zostera2" etc.
top.sp.abnd.glms.lvm.zostera.2 <- lapply(top.sp.abnd.glms.lvm.zostera.2, function(x) x %>% rename_at(vars(contains("lvm.clusters.zostera.2")), list(~str_replace_all(., pattern = "lvm.clusters.zostera.2", "group_"))))
top.sp.abnd.glms.lvm.zostera.2 <- lapply(top.sp.abnd.glms.lvm.zostera.2, function(x) x %>% rename_at(vars(contains("Intercept")), list(~str_replace_all(., pattern = "\\(Intercept\\)", "group_1"))))
## pull the abundances from the original count df and add to the summary glm tables 
## make a long df of abundances & add clusters  
zoo.abnd.zostera.long.2 <- zoo.abnd.zostera %>%
  select(-c(month:replicate)) %>%
  gather(key = "species", value = "count", -station) %>% 
  mutate(group = case_when(station == "Poda" ~ 1,
                           station == "Otmanli" ~ 2, 
                           station == "Vromos" ~ 3, 
                           station == "Gradina" ~ 4, 
                           station == "Ropotamo" ~ 5)
         )
## sum sp abundances by group; nest by group
zoo.abnd.zostera.long.2.smry <- zoo.abnd.zostera.long.2 %>% 
  group_by(species, group) %>% 
  summarise(total_count = sum(count)) %>% 
  group_by(group) %>%
  nest()
## add the counts to the group dfs - wow that's an ugly, ugly hack. Wish I had more time to write this up properly.. 
top.sp.abnd.glms.lvm.zostera.2 <- map2(top.sp.abnd.glms.lvm.zostera.2, zoo.abnd.zostera.long.2.smry %>% pull(group), ~left_join(.x, zoo.abnd.zostera.long.2.smry %>% filter(group == .y) %>% unnest(), by = "species"))
## since these are sum counts over all the replicates (that's why the monstrous numbers), average them to be mean counts per group. NB different groups consist of different numbers of replicates, b.c. some groups consist of more than one station
(top.sp.abnd.glms.lvm.zostera.2 <- map2(top.sp.abnd.glms.lvm.zostera.2, c(8, 8, 4, 8, 4), function(x, y) x %>% mutate(mean_count = total_count/y))
)
[[1]]

[[2]]

[[3]]

[[4]]

[[5]]
NA

In the case of the seagrasses and case 2 clusters (= stations), the picture is still more unclear.. I suppose this is in no small part because of the differences 2013-14 - very marked for Poda and Otmanli. I suspect the stations changed in these two years (we were looking for Z. noltii in 2014 in particular) - but still, there is much variability. In the future, it’s probably going to be worth it to have more stations in a meadow, if we really want to have an idea of the communities there, and their variability.
The LRs seem to be a bit lower for groups 2, 4, maybe 5 too - still not sure if you can use that as a significance measure.
For now, in group 1 (= Z1), it’s hard to pick some characteristic species - because of the variability between 2013-2014, no doubt. The species/taxa with significantly higher abundance are: Bittium reticulatum, Capitella minima, Polydora ciliata, Prionosprio cirrifera (+ others, medium abundance); and the ones with a significantly lower abundance - or even absent - C. gallina, A. ostroumovi, S. clavata, C. limicola, C. costulata, S. hystrix, S. gracilis, T. pullus.
For group 2 (= Z2), the species with higher abundance - which is not really all that high; this group is also loose, hard to distinguish from group 1 - are: S. gracilis, M. lineatus, P. ciliata. The only species with lower abundance - in fact 0 - is Alitta succinea.
For group 3 (= Z3), the species with higher abundance are: M. acherusicum, S. filicornis, A. diadema. The species with lower abundance (or 0) are: B. reticulatum, P. ciliata, P. cirrifera, A. alba, A. succiena, S. clavata, Oligochaeta, A. improvisus.
For group 4 (= Z4), the species with higher abundance are: M. lineatus (very much so); C. limicola, P. kefersteini, C. gallina, C. capitata. The species with lower abundance (or 0) are: P. ciliata, P. cirrifera, A. succinea, A. improvisus, A. alba.
For group 5 (= Z5), the species with higher abundance are: A. ostroumovi, C. capitata, Oligochaeta. The species with lower abundance (or 0) are: R. splendida, T. pullus.

LVM clusters - case 3 Last try: group 1 = Z1-Z2, group 2 = Z3, group 3 = Z4, group 4 = Z5.
Check the model assumptions.

plot(manyglm(zoo.mvabnd.zostera ~ lvm.clusters.zostera.3, family = "negative.binomial"))

meanvar.plot(zoo.mvabnd.zostera ~ lvm.clusters.zostera.3, table = TRUE)

More or less the same as case 2 before it.

  1. Assumed relationship between mean abundance and environmental variables - link function and formula.

Everything looks more or less fine; fit the model.

glms.lvm.zostera.3 <- manyglm(zoo.mvabnd.zostera ~ lvm.clusters.zostera.3, 
                              family = "negative.binomial")

Explore the fit (residuals, diagnostic plots, etc.).

## residuals vs fitted values
plot(glms.lvm.zostera.3)

## all traditional (g)lm diagnostic plots
plot.manyglm(glms.lvm.zostera.3, which = 1:3)

# ### source mvabund GLM plotting functions modified to use a grey palette - I just can't redo these plots on my own, the function is doing too complicated things internally to scale the x and y axes
# source(here(functions.dir, "default.plot.manyglm_grey.R"))
# source(here(functions.dir, "plot.manyglm_grey.R"))
# 
# par(mfrow = c(3,3))
# lapply(3:3, function(i) plot.manyglm.grey(glms.lvm.zostera, which = i, sub.caption = ""))
# par(mfrow = c(3, 3))

Save the model!

write_rds(glms.lvm.zostera.3, 
          here(save.dir, "glms_lvm_zostera_3.RDS"))

Let’s see the model summary (NB takes a LOT of time if there are many resamplings!).

(glms.lvm.zostera.3.summary <- summary(glms.lvm.zostera.3, 
                                       test = "LR", p.uni = "adjusted",
                                       nBoot = 999, ## limit the number of permutations if you just want to check it out
                                       show.time = "all")
)

The factor is highly significant according to the models.

Again, save the summary for safekeeping, but also run an anova.

write_rds(glms.lvm.zostera.3.summary, 
          here(save.dir, "glms_lvm_zostera_3_summary.RDS"))

Run the anova on the model.

(glms.lvm.zostera.3.aov <- anova.manyglm(glms.lvm.zostera.3, 
                                         test = "LR", p.uni = "adjusted", 
                                         nBoot = 999, ## limit the number of permutations for a shorter run time   
                                         pairwise.comp = ~lvm.clusters.zostera.3, ## check the pairwise comparisons between clusters
                                         show.time = "all") 
)
Resampling begins for test 1.
    Resampling run 0 finished. Time elapsed: 0.00 minutes...
    Resampling run 100 finished. Time elapsed: 0.12 minutes...
    Resampling run 200 finished. Time elapsed: 0.24 minutes...
    Resampling run 300 finished. Time elapsed: 0.37 minutes...
    Resampling run 400 finished. Time elapsed: 0.50 minutes...
    Resampling run 500 finished. Time elapsed: 0.63 minutes...
    Resampling run 600 finished. Time elapsed: 0.75 minutes...
    Resampling run 700 finished. Time elapsed: 0.88 minutes...
    Resampling run 800 finished. Time elapsed: 1.00 minutes...
    Resampling run 900 finished. Time elapsed: 1.13 minutes...
Time elapsed: 0 hr 1 min 15 sec
Analysis of Deviance Table

Model: manyglm(formula = zoo.mvabnd.zostera ~ lvm.clusters.zostera.3, 
Model:     family = "negative.binomial")

Multivariate test:
                       Res.Df Df.diff   Dev Pr(>Dev)    
(Intercept)                31                           
lvm.clusters.zostera.3     28       3 965.7    0.001 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Pairwise comparison results: 
                                                     Observed statistic
lvm.clusters.zostera.3:2 vs lvm.clusters.zostera.3:3              368.1
lvm.clusters.zostera.3:1 vs lvm.clusters.zostera.3:3              355.8
lvm.clusters.zostera.3:2 vs lvm.clusters.zostera.3:4              336.6
lvm.clusters.zostera.3:1 vs lvm.clusters.zostera.3:2              319.4
lvm.clusters.zostera.3:3 vs lvm.clusters.zostera.3:4              295.1
lvm.clusters.zostera.3:1 vs lvm.clusters.zostera.3:4              275.0
                                                     Free Stepdown Adjusted P-Value   
lvm.clusters.zostera.3:2 vs lvm.clusters.zostera.3:3                          0.007 **
lvm.clusters.zostera.3:1 vs lvm.clusters.zostera.3:3                          0.007 **
lvm.clusters.zostera.3:2 vs lvm.clusters.zostera.3:4                          0.010 **
lvm.clusters.zostera.3:1 vs lvm.clusters.zostera.3:2                          0.010 **
lvm.clusters.zostera.3:3 vs lvm.clusters.zostera.3:4                          0.010 **
lvm.clusters.zostera.3:1 vs lvm.clusters.zostera.3:4                          0.010 **
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1


Univariate Tests:
                       Abra.alba          Abra.sp.          Actiniaria         
                             Dev Pr(>Dev)      Dev Pr(>Dev)        Dev Pr(>Dev)
(Intercept)                                                                    
lvm.clusters.zostera.3    27.438    0.002    4.159    1.000      1.386    1.000
                       Alitta.succinea          Ampelisca.diadema         
                                   Dev Pr(>Dev)               Dev Pr(>Dev)
(Intercept)                                                               
lvm.clusters.zostera.3          13.528    0.170            20.153    0.014
                       Amphibalanus.improvisus          Ampithoe.sp.         
                                           Dev Pr(>Dev)          Dev Pr(>Dev)
(Intercept)                                                                  
lvm.clusters.zostera.3                  15.231    0.098        8.727    0.657
                       Anadara.kagoshimensis          Apherusa.bispinosa         
                                         Dev Pr(>Dev)                Dev Pr(>Dev)
(Intercept)                                                                      
lvm.clusters.zostera.3                 1.386    1.000              2.773    1.000
                       Apseudopsis.ostroumovi          Bittium.reticulatum         
                                          Dev Pr(>Dev)                 Dev Pr(>Dev)
(Intercept)                                                                        
lvm.clusters.zostera.3                 51.414    0.001              34.189    0.001
                       Brachynotus.sexdentatus          Capitella.capitata         
                                           Dev Pr(>Dev)                Dev Pr(>Dev)
(Intercept)                                                                        
lvm.clusters.zostera.3                   1.386    1.000             30.336    0.001
                       Capitella.minima          Chamelea.gallina         
                                    Dev Pr(>Dev)              Dev Pr(>Dev)
(Intercept)                                                               
lvm.clusters.zostera.3            6.793    0.868           27.138    0.002
                       Chironomidae.larvae          Cumella.limicola         
                                       Dev Pr(>Dev)              Dev Pr(>Dev)
(Intercept)                                                                  
lvm.clusters.zostera.3               9.651    0.539           33.634    0.001
                       Cumella.pygmaea          Cytharella.costulata         
                                   Dev Pr(>Dev)                  Dev Pr(>Dev)
(Intercept)                                                                  
lvm.clusters.zostera.3           6.118    0.940                3.195    1.000
                       Diogenes.pugilator          Eteone.flava          Eunice.vittata
                                      Dev Pr(>Dev)          Dev Pr(>Dev)            Dev
(Intercept)                                                                            
lvm.clusters.zostera.3               2.38    1.000        4.159    1.000          3.572
                                Eurydice.dollfusi          Exogone.naidina         
                       Pr(>Dev)               Dev Pr(>Dev)             Dev Pr(>Dev)
(Intercept)                                                                        
lvm.clusters.zostera.3    1.000             6.118    0.940           7.227    0.845
                       Gastrosaccus.sanctus          Genetyllis.tuberculata         
                                        Dev Pr(>Dev)                    Dev Pr(>Dev)
(Intercept)                                                                         
lvm.clusters.zostera.3                2.773    1.000                  1.966    1.000
                       Glycera.sp.          Glycera.tridactyla         
                               Dev Pr(>Dev)                Dev Pr(>Dev)
(Intercept)                                                            
lvm.clusters.zostera.3       7.992    0.753              4.484    0.997
                       Glycera.unicornis          Harmothoe.imbricata         
                                     Dev Pr(>Dev)                 Dev Pr(>Dev)
(Intercept)                                                                   
lvm.clusters.zostera.3             1.386    1.000               3.192    1.000
                       Harmothoe.reticulata          Heteromastus.filiformis         
                                        Dev Pr(>Dev)                     Dev Pr(>Dev)
(Intercept)                                                                          
lvm.clusters.zostera.3                9.416    0.574                  17.463    0.039
                       Hirudinea          Hydrobia.acuta          Hydrobia.sp.         
                             Dev Pr(>Dev)            Dev Pr(>Dev)          Dev Pr(>Dev)
(Intercept)                                                                            
lvm.clusters.zostera.3     1.726    1.000          1.438    1.000         2.25    1.000
                       Iphinoe.tenella          Kellia.suborbicularis         
                                   Dev Pr(>Dev)                   Dev Pr(>Dev)
(Intercept)                                                                   
lvm.clusters.zostera.3            5.47    0.985                 8.973    0.633
                       Lagis.koreni          Leiochone.leiopygos         
                                Dev Pr(>Dev)                 Dev Pr(>Dev)
(Intercept)                                                              
lvm.clusters.zostera.3       10.472    0.426              14.995    0.102
                       Lentidium.mediterraneum          Lepidochitona.cinerea         
                                           Dev Pr(>Dev)                   Dev Pr(>Dev)
(Intercept)                                                                           
lvm.clusters.zostera.3                   5.545    0.978                 2.773    1.000
                       Loripes.orbiculatus          Lucinella.divaricata         
                                       Dev Pr(>Dev)                  Dev Pr(>Dev)
(Intercept)                                                                      
lvm.clusters.zostera.3              28.176    0.002                6.172    0.935
                       Magelona.papillicornis          Maldane.glebifex         
                                          Dev Pr(>Dev)              Dev Pr(>Dev)
(Intercept)                                                                     
lvm.clusters.zostera.3                  2.773    1.000            1.386    1.000
                       Melinna.palmata          Microdeutopus.gryllotalpa         
                                   Dev Pr(>Dev)                       Dev Pr(>Dev)
(Intercept)                                                                       
lvm.clusters.zostera.3          24.203    0.006                    13.747    0.156
                       Micromaldane.ornithochaeta          Micronephthys.stammeri
                                              Dev Pr(>Dev)                    Dev
(Intercept)                                                                      
lvm.clusters.zostera.3                      6.655    0.888                  2.773
                                Microphthalmus.fragilis          Microphthalmus.sp.
                       Pr(>Dev)                     Dev Pr(>Dev)                Dev
(Intercept)                                                                        
lvm.clusters.zostera.3    1.000                   1.437    1.000             11.855
                                Monocorophium.acherusicum          Mytilaster.lineatus
                       Pr(>Dev)                       Dev Pr(>Dev)                 Dev
(Intercept)                                                                           
lvm.clusters.zostera.3    0.280                    39.678    0.001               34.91
                                Mytilus.galloprovincialis          Nemertea         
                       Pr(>Dev)                       Dev Pr(>Dev)      Dev Pr(>Dev)
(Intercept)                                                                         
lvm.clusters.zostera.3    0.001                     1.386    1.000    4.566    0.996
                       Nephtys.cirrosa          Nephtys.kersivalensis         
                                   Dev Pr(>Dev)                   Dev Pr(>Dev)
(Intercept)                                                                   
lvm.clusters.zostera.3           1.386    1.000                 1.386    1.000
                       Nereis.perivisceralis          Nereis.pulsatoria         
                                         Dev Pr(>Dev)               Dev Pr(>Dev)
(Intercept)                                                                     
lvm.clusters.zostera.3                 2.773    1.000             2.987    1.000
                       Nototropis.guttatus          Oligochaeta         
                                       Dev Pr(>Dev)         Dev Pr(>Dev)
(Intercept)                                                             
lvm.clusters.zostera.3               7.095    0.848      27.378    0.002
                       Paradoneis.harpagonea          Parthenina.interstincta         
                                         Dev Pr(>Dev)                     Dev Pr(>Dev)
(Intercept)                                                                           
lvm.clusters.zostera.3                 1.386    1.000                   2.884    1.000
                       Parvicardium.exiguum          Perinereis.cultrifera         
                                        Dev Pr(>Dev)                   Dev Pr(>Dev)
(Intercept)                                                                        
lvm.clusters.zostera.3                2.911    1.000                 4.654    0.994
                       Perioculodes.longimanus          Phoronida         
                                           Dev Pr(>Dev)       Dev Pr(>Dev)
(Intercept)                                                               
lvm.clusters.zostera.3                   4.365    0.997     5.372    0.987
                       Phyllodoce.sp.          Platyhelminthes         
                                  Dev Pr(>Dev)             Dev Pr(>Dev)
(Intercept)                                                            
lvm.clusters.zostera.3          4.159    1.000           5.906    0.946
                       Platynereis.dumerilii          Polititapes.aureus         
                                         Dev Pr(>Dev)                Dev Pr(>Dev)
(Intercept)                                                                      
lvm.clusters.zostera.3                 8.537    0.673              4.065    1.000
                       Polychaeta.larvae          Polydora.ciliata         
                                     Dev Pr(>Dev)              Dev Pr(>Dev)
(Intercept)                                                                
lvm.clusters.zostera.3             4.159    1.000           29.489    0.002
                       Polygordius.neapolitanus          Prionospio.cirrifera         
                                            Dev Pr(>Dev)                  Dev Pr(>Dev)
(Intercept)                                                                           
lvm.clusters.zostera.3                    4.159    1.000               41.351    0.001
                       Protodorvillea.kefersteini          Pseudocuma.longicorne
                                              Dev Pr(>Dev)                   Dev
(Intercept)                                                                     
lvm.clusters.zostera.3                     25.261    0.006                 1.726
                                Rissoa.membranacea          Rissoa.splendida         
                       Pr(>Dev)                Dev Pr(>Dev)              Dev Pr(>Dev)
(Intercept)                                                                          
lvm.clusters.zostera.3    1.000              1.701    1.000           17.118    0.046
                       Salvatoria.clavata          Schistomeringos.rudolphi         
                                      Dev Pr(>Dev)                      Dev Pr(>Dev)
(Intercept)                                                                         
lvm.clusters.zostera.3             32.959    0.001                    5.024    0.990
                       Sphaerosyllis.hystrix          Spio.filicornis         
                                         Dev Pr(>Dev)             Dev Pr(>Dev)
(Intercept)                                                                   
lvm.clusters.zostera.3                12.736    0.208          34.632    0.001
                       Spisula.subtruncata          Stenosoma.capito         
                                       Dev Pr(>Dev)              Dev Pr(>Dev)
(Intercept)                                                                  
lvm.clusters.zostera.3               5.885    0.946            7.189    0.848
                       Syllis.gracilis          Syllis.hyalina          Tellina.tenuis
                                   Dev Pr(>Dev)            Dev Pr(>Dev)            Dev
(Intercept)                                                                           
lvm.clusters.zostera.3          10.712    0.392          4.555    0.996          3.112
                                Thracia.phaseolina          Tricolia.pullus         
                       Pr(>Dev)                Dev Pr(>Dev)             Dev Pr(>Dev)
(Intercept)                                                                         
lvm.clusters.zostera.3    1.000              2.773    1.000          13.288    0.177
                       Tritia.neritea          Tritia.reticulata          Turbellaria
                                  Dev Pr(>Dev)               Dev Pr(>Dev)         Dev
(Intercept)                      <NA>     <NA>              <NA>     <NA>        <NA>
lvm.clusters.zostera.3          2.037    1.000             2.932    1.000       1.527
                                Upogebia.pusilla         
                       Pr(>Dev)              Dev Pr(>Dev)
(Intercept)                <NA>             <NA>     <NA>
lvm.clusters.zostera.3    1.000           10.026    0.466
Arguments:
 Test statistics calculated assuming uncorrelated response (for faster computation) 
P-value calculated using 999 resampling iterations via PIT-trap resampling (to account for correlation in testing.

According to the pairwise comparison, the case 3 clusters are significantly different from one another.. apparently sufficiently so.

Save the ANOVA, too.

write_rds(glms.lvm.zostera.3.aov, 
          here(save.dir, "glms_lvm_zostera_3_anova.RDS"))

NOW let’s get the taxa with the highest contributions to the tested pattern.

## get the top contributing species for the initial zostera GLMs 
(top.sp.glms.lvm.zostera.3 <- top_n_sp_glm(glms.lvm.zostera.3.aov, tot.dev.expl = 0.75)
)
[1] "Total deviance explained: 0.82"
    Apseudopsis.ostroumovi       Prionospio.cirrifera  Monocorophium.acherusicum 
                 51.413970                  41.350974                  39.678240 
       Mytilaster.lineatus            Spio.filicornis        Bittium.reticulatum 
                 34.909870                  34.632433                  34.188511 
          Cumella.limicola         Salvatoria.clavata         Capitella.capitata 
                 33.633823                  32.958829                  30.336457 
          Polydora.ciliata        Loripes.orbiculatus                  Abra.alba 
                 29.489490                  28.175552                  27.437828 
               Oligochaeta           Chamelea.gallina Protodorvillea.kefersteini 
                 27.378351                  27.138297                  25.260955 
           Melinna.palmata          Ampelisca.diadema    Heteromastus.filiformis 
                 24.202974                  20.153373                  17.463258 
          Rissoa.splendida    Amphibalanus.improvisus        Leiochone.leiopygos 
                 17.117581                  15.231072                  14.994968 
 Microdeutopus.gryllotalpa            Alitta.succinea            Tricolia.pullus 
                 13.746930                  13.527612                  13.287785 
     Sphaerosyllis.hystrix         Microphthalmus.sp.            Syllis.gracilis 
                 12.736427                  11.854688                  10.711746 
              Lagis.koreni           Upogebia.pusilla        Chironomidae.larvae 
                 10.471907                  10.025894                   9.650905 
      Harmothoe.reticulata      Kellia.suborbicularis               Ampithoe.sp. 
                  9.416160                   8.973262                   8.726571 
     Platynereis.dumerilii                Glycera.sp.            Exogone.naidina 
                  8.536643                   7.992056                   7.227403 
          Stenosoma.capito        Nototropis.guttatus           Capitella.minima 
                  7.189015                   7.094867                   6.793482 
Micromaldane.ornithochaeta 
                  6.655076 
## unfortunately, mvabund likes to rename my species when converting the data to matrix (no spaces in names), and since I'm going to look them up in my initial untransformed count data, I have to change them back..   
names(top.sp.glms.lvm.zostera.3) <- names(top.sp.glms.lvm.zostera.3) %>% 
  str_replace(pattern = "\\.", replacement = " ")
top.sp.glms.lvm.zostera.3
    Apseudopsis ostroumovi       Prionospio cirrifera  Monocorophium acherusicum 
                 51.413970                  41.350974                  39.678240 
       Mytilaster lineatus            Spio filicornis        Bittium reticulatum 
                 34.909870                  34.632433                  34.188511 
          Cumella limicola         Salvatoria clavata         Capitella capitata 
                 33.633823                  32.958829                  30.336457 
          Polydora ciliata        Loripes orbiculatus                  Abra alba 
                 29.489490                  28.175552                  27.437828 
               Oligochaeta           Chamelea gallina Protodorvillea kefersteini 
                 27.378351                  27.138297                  25.260955 
           Melinna palmata          Ampelisca diadema    Heteromastus filiformis 
                 24.202974                  20.153373                  17.463258 
          Rissoa splendida    Amphibalanus improvisus        Leiochone leiopygos 
                 17.117581                  15.231072                  14.994968 
 Microdeutopus gryllotalpa            Alitta succinea            Tricolia pullus 
                 13.746930                  13.527612                  13.287785 
     Sphaerosyllis hystrix         Microphthalmus sp.            Syllis gracilis 
                 12.736427                  11.854688                  10.711746 
              Lagis koreni           Upogebia pusilla        Chironomidae larvae 
                 10.471907                  10.025894                   9.650905 
      Harmothoe reticulata      Kellia suborbicularis               Ampithoe sp. 
                  9.416160                   8.973262                   8.726571 
     Platynereis dumerilii                Glycera sp.            Exogone naidina 
                  8.536643                   7.992056                   7.227403 
          Stenosoma capito        Nototropis guttatus           Capitella minima 
                  7.189015                   7.094867                   6.793482 
Micromaldane ornithochaeta 
                  6.655076 

Try to plot these top contributing species - for whatever that’s worth, because 50 species on a plot is still a monstrosity.

## get the species and their abundances from the original count data, and transform them to long format
(abnd.top.sp.glms.lvm.zostera.3 <- zoo.abnd.zostera %>% 
   select(station, names(top.sp.glms.lvm.zostera.3)) %>% 
   gather(key = "species", value = "count", -station) %>% 
   ## turn species into a factor, or you'll be very very sorry later, when they're out of order on the plot. NB need to be in REVERSE order, because ggplot plots from bottom to top, and I want the top-contributing species on top. 
   mutate(species = factor(species, levels = rev(names(top.sp.glms.lvm.zostera.3)))) %>% 
   mutate(group = factor(case_when(station %in% c("Poda", "Otmanli") ~ 1,
                                   station == "Vromos" ~ 2, 
                                   station == "Gradina" ~ 3, 
                                   station == "Ropotamo" ~ 4)) ## add the groups
          )
)
(plot.top.sp.glms.lvm.zostera.3 <- plot_top_n(abnd.top.sp.glms.lvm.zostera.3,
                                              mapping = aes(x = species, y = log_y_min(count), colour = group),
                                              labs.legend = paste0("group", as.character(levels(abnd.top.sp.glms.lvm.zostera.3$group))),
                                              lab.y = "Abundance (log(y/min + 1))",
                                              palette = "Set2"
                                        ) +
    theme(legend.position = "top", legend.title = element_blank())
)

Extract the top-contributing species to each cluster (this same nightmare above, but as a table). This chunk is STILL hopelessly ugly and clumsy.

top.sp.abnd.glms.lvm.zostera.3 <- lapply(names(glms.lvm.zostera.3.summary$aliased), function(x) top_sp_glms_table(glms.lvm.zostera.3.summary, x, p = 0.05)) 
## fix species names (remove dot) 
top.sp.abnd.glms.lvm.zostera.3 <- lapply(top.sp.abnd.glms.lvm.zostera.3, function(x) x %>% mutate(species = str_replace(species, pattern = "\\.", replacement = " ")))
## rename columns (= group names) - right now they are something like "lvm.clusters.zostera3" etc.
top.sp.abnd.glms.lvm.zostera.3 <- lapply(top.sp.abnd.glms.lvm.zostera.3, function(x) x %>% rename_at(vars(contains("lvm.clusters.zostera.3")), list(~str_replace_all(., pattern = "lvm.clusters.zostera.3", "group_"))))
top.sp.abnd.glms.lvm.zostera.3 <- lapply(top.sp.abnd.glms.lvm.zostera.3, function(x) x %>% rename_at(vars(contains("Intercept")), list(~str_replace_all(., pattern = "\\(Intercept\\)", "group_1"))))
## pull the abundances from the original count df and add to the summary glm tables 
## make a long df of abundances & add clusters  
zoo.abnd.zostera.long.3 <- zoo.abnd.zostera %>%
  select(-c(month:replicate)) %>%
  gather(key = "species", value = "count", -station) %>% 
  mutate(group = case_when(station %in% c("Poda", "Otmanli") ~ 1,
                           station == "Vromos" ~ 2, 
                           station == "Gradina" ~ 3, 
                           station == "Ropotamo" ~ 4)
         )
## sum sp abundances by group; nest by group
zoo.abnd.zostera.long.3.smry <- zoo.abnd.zostera.long.3 %>% 
  group_by(species, group) %>% 
  summarise(total_count = sum(count)) %>% 
  group_by(group) %>%
  nest()
## add the counts to the group dfs - wow that's an ugly, ugly hack. Wish I had more time to write this up properly.. 
top.sp.abnd.glms.lvm.zostera.3 <- map2(top.sp.abnd.glms.lvm.zostera.3, zoo.abnd.zostera.long.3.smry %>% pull(group), ~left_join(.x, zoo.abnd.zostera.long.3.smry %>% filter(group == .y) %>% unnest(), by = "species"))
## since these are sum counts over all the replicates (that's why the monstrous numbers), average them to be mean counts per group. NB different groups consist of different numbers of replicates, b.c. some groups consist of more than one station
(top.sp.abnd.glms.lvm.zostera.3 <- map2(top.sp.abnd.glms.lvm.zostera.3, c(16, 4, 8, 4), function(x, y) x %>% mutate(mean_count = total_count/y))
)
[[1]]

[[2]]

[[3]]

[[4]]
NA

In the case of the seagrasses and case 3 clusters, the picture is still more confusing..
The LRs seem to be a bit lower for groups 2 and 3, maybe 4 too - still not sure if you can use that as a significance measure.
For now, in group 1 (= Z1-Z2), the species/taxa with significantly higher abundance are: Bittium reticulatum, Capitella minima, Oligochaeta, Heteromastus filiformis, Polydora ciliata, Prionosprio cirrifera, Rissoa membranacea, Abra alba, Ampelisca diadema (+ others, medium abundance); and the ones with a significantly lower abundance - or even absent - S. clavata, A. ostroumovi, C. gallina, T. pullus.
There are more species singled out for this cluster, probably because of the variability between the two years of sampling.
For group 2 (= Z3), the species with higher abundance are: M. acherusicum, S. filicornis, A. diadema. The species with lower abundance - in fact 0 - are B. reticulatum, P. cirrifera, S. clavata, A. alba, P. ciliata, oligochaetes, H. filiformis, R. splendida.
For group 3 (= Z4), the species with higher abundance are: M. lineatus, less so - C. limicola, L. orbiculatus, P. kefersteini, C. capitata, etc. The species with lower abundance (or 0) are: P. cirrifera, P. ciliata, A. alba, etc.
For group 4 (= Z5), the species with higher abundance are: A. ostoumovi, C. capitata, oligochaetes (very abundant, but with a small LR - nice!). The species with lower abundance (or 0) are: R. splendida, S. clavata, C. limicola.

All in all, I think that group 1 (Poda + Otmanli) holds, and so does group 2 (Vromos). The question is whether to separate Gradina and Ropotamo into 2 groups, or if they make more sense together. Ropotamo is characterized by a very high number of oligochaetes, while Gradina’s most distinguishing characteristic is the high number of M. lineatus - mostly very small ones, attached to the rhizomes, close to the sediment surface I presume. Both stations have C. limicola in medium abundance, a species that is not present anywhere else (is it?).

Try to compare the three models..

(glms.lvm.zostera.comp <- anova(glms.lvm.zostera.1,
                                glms.lvm.zostera.2, 
                                glms.lvm.zostera.3, 
                                p.uni = "adjusted")
)
Time elapsed: 0 hr 2 min 22 sec
Analysis of Deviance Table

glms.lvm.zostera.1: zoo.mvabnd.zostera ~ lvm.clusters.zostera.1
glms.lvm.zostera.3: zoo.mvabnd.zostera ~ lvm.clusters.zostera.3
glms.lvm.zostera.2: zoo.mvabnd.zostera ~ lvm.clusters.zostera.2

Multivariate test:
                   Res.Df Df.diff   Dev Pr(>Dev)    
glms.lvm.zostera.1     29                           
glms.lvm.zostera.3     28       1 262.1    0.001 ***
glms.lvm.zostera.2     27       1 256.8    0.001 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Univariate Tests:
                   Abra.alba          Abra.sp.          Actiniaria         
                         Dev Pr(>Dev)      Dev Pr(>Dev)        Dev Pr(>Dev)
glms.lvm.zostera.1                                                         
glms.lvm.zostera.3     1.506    0.998        0    1.000          0    1.000
glms.lvm.zostera.2     0.023    1.000        0    1.000      1.386    1.000
                   Alitta.succinea          Ampelisca.diadema         
                               Dev Pr(>Dev)               Dev Pr(>Dev)
glms.lvm.zostera.1                                                    
glms.lvm.zostera.3           4.881    0.681             0.094    1.000
glms.lvm.zostera.2          23.057    0.001            10.416    0.104
                   Amphibalanus.improvisus          Ampithoe.sp.         
                                       Dev Pr(>Dev)          Dev Pr(>Dev)
glms.lvm.zostera.1                                                       
glms.lvm.zostera.3                   0.349    1.000        2.405    0.982
glms.lvm.zostera.2                   8.177    0.251        3.482    0.917
                   Anadara.kagoshimensis          Apherusa.bispinosa         
                                     Dev Pr(>Dev)                Dev Pr(>Dev)
glms.lvm.zostera.1                                                           
glms.lvm.zostera.3                     0    1.000              0.811    1.000
glms.lvm.zostera.2                 1.386    1.000                  0    1.000
                   Apseudopsis.ostroumovi          Bittium.reticulatum         
                                      Dev Pr(>Dev)                 Dev Pr(>Dev)
glms.lvm.zostera.1                                                             
glms.lvm.zostera.3                 20.559    0.001               3.006    0.941
glms.lvm.zostera.2                   1.38    1.000               0.004    1.000
                   Brachynotus.sexdentatus          Capitella.capitata         
                                       Dev Pr(>Dev)                Dev Pr(>Dev)
glms.lvm.zostera.1                                                             
glms.lvm.zostera.3                   0.811    1.000              4.124    0.814
glms.lvm.zostera.2                   1.386    1.000              2.862    0.958
                   Capitella.minima          Chamelea.gallina         
                                Dev Pr(>Dev)              Dev Pr(>Dev)
glms.lvm.zostera.1                                                    
glms.lvm.zostera.3            6.055    0.518            0.908    1.000
glms.lvm.zostera.2            0.433    1.000            1.386    0.996
                   Chironomidae.larvae          Cumella.limicola         
                                   Dev Pr(>Dev)              Dev Pr(>Dev)
glms.lvm.zostera.1                                                       
glms.lvm.zostera.3               5.456    0.615            1.089    1.000
glms.lvm.zostera.2                   0    1.000            7.694    0.306
                   Cumella.pygmaea          Cytharella.costulata         
                               Dev Pr(>Dev)                  Dev Pr(>Dev)
glms.lvm.zostera.1                                                       
glms.lvm.zostera.3           1.891    0.996                0.073    1.000
glms.lvm.zostera.2               0    1.000                4.159    0.834
                   Diogenes.pugilator          Eteone.flava          Eunice.vittata
                                  Dev Pr(>Dev)          Dev Pr(>Dev)            Dev
glms.lvm.zostera.1                                                                 
glms.lvm.zostera.3              1.483    0.999            0    1.000            2.7
glms.lvm.zostera.2               0.68    1.000            0    1.000          0.208
                            Eurydice.dollfusi          Exogone.naidina         
                   Pr(>Dev)               Dev Pr(>Dev)             Dev Pr(>Dev)
glms.lvm.zostera.1                                                             
glms.lvm.zostera.3    0.959             1.891    0.996           1.284    1.000
glms.lvm.zostera.2    1.000                 0    1.000            1.25    1.000
                   Gastrosaccus.sanctus          Genetyllis.tuberculata         
                                    Dev Pr(>Dev)                    Dev Pr(>Dev)
glms.lvm.zostera.1                                                              
glms.lvm.zostera.3                0.811    1.000                  1.499    0.998
glms.lvm.zostera.2                    0    1.000                  5.746    0.574
                   Glycera.sp.          Glycera.tridactyla          Glycera.unicornis
                           Dev Pr(>Dev)                Dev Pr(>Dev)               Dev
glms.lvm.zostera.1                                                                   
glms.lvm.zostera.3           0    1.000                  0    1.000                 0
glms.lvm.zostera.2           0    1.000              1.033    1.000             1.386
                            Harmothoe.imbricata          Harmothoe.reticulata         
                   Pr(>Dev)                 Dev Pr(>Dev)                  Dev Pr(>Dev)
glms.lvm.zostera.1                                                                    
glms.lvm.zostera.3    1.000               1.352    1.000                4.286    0.796
glms.lvm.zostera.2    1.000               5.561    0.595                5.794    0.566
                   Heteromastus.filiformis          Hirudinea          Hydrobia.acuta
                                       Dev Pr(>Dev)       Dev Pr(>Dev)            Dev
glms.lvm.zostera.1                                                                   
glms.lvm.zostera.3                   7.242    0.334     0.811    1.000              0
glms.lvm.zostera.2                  10.679    0.088         0    1.000          1.494
                            Hydrobia.sp.          Iphinoe.tenella         
                   Pr(>Dev)          Dev Pr(>Dev)             Dev Pr(>Dev)
glms.lvm.zostera.1                                                        
glms.lvm.zostera.3    1.000        0.569    1.000            1.31    1.000
glms.lvm.zostera.2    0.996        3.709    0.906           4.354    0.811
                   Kellia.suborbicularis          Lagis.koreni         
                                     Dev Pr(>Dev)          Dev Pr(>Dev)
glms.lvm.zostera.1                                                     
glms.lvm.zostera.3                 4.389    0.796        0.767    1.000
glms.lvm.zostera.2                 0.104    1.000        5.999    0.554
                   Leiochone.leiopygos          Lentidium.mediterraneum         
                                   Dev Pr(>Dev)                     Dev Pr(>Dev)
glms.lvm.zostera.1                                                              
glms.lvm.zostera.3               8.777    0.194                   1.622    0.997
glms.lvm.zostera.2               0.336    1.000                       0    1.000
                   Lepidochitona.cinerea          Loripes.orbiculatus         
                                     Dev Pr(>Dev)                 Dev Pr(>Dev)
glms.lvm.zostera.1                                                            
glms.lvm.zostera.3                 0.811    1.000               2.917    0.948
glms.lvm.zostera.2                     0    1.000               3.172    0.936
                   Lucinella.divaricata          Magelona.papillicornis         
                                    Dev Pr(>Dev)                    Dev Pr(>Dev)
glms.lvm.zostera.1                                                              
glms.lvm.zostera.3                1.915    0.995                  0.811    1.000
glms.lvm.zostera.2                    0    1.000                      0    1.000
                   Maldane.glebifex          Melinna.palmata         
                                Dev Pr(>Dev)             Dev Pr(>Dev)
glms.lvm.zostera.1                                                   
glms.lvm.zostera.3                0    1.000               0    1.000
glms.lvm.zostera.2            1.386    0.999           2.657    0.983
                   Microdeutopus.gryllotalpa          Micromaldane.ornithochaeta
                                         Dev Pr(>Dev)                        Dev
glms.lvm.zostera.1                                                              
glms.lvm.zostera.3                    10.659    0.065                      2.111
glms.lvm.zostera.2                     2.603    0.984                          0
                            Micronephthys.stammeri          Microphthalmus.fragilis
                   Pr(>Dev)                    Dev Pr(>Dev)                     Dev
glms.lvm.zostera.1                                                                 
glms.lvm.zostera.3    0.995                  2.197    0.994                       0
glms.lvm.zostera.2    1.000                  1.386    1.000                   1.494
                            Microphthalmus.sp.          Monocorophium.acherusicum
                   Pr(>Dev)                Dev Pr(>Dev)                       Dev
glms.lvm.zostera.1                                                               
glms.lvm.zostera.3    1.000              2.459    0.979                      1.35
glms.lvm.zostera.2    0.996                  0    1.000                     0.213
                            Mytilaster.lineatus          Mytilus.galloprovincialis
                   Pr(>Dev)                 Dev Pr(>Dev)                       Dev
glms.lvm.zostera.1                                                                
glms.lvm.zostera.3    1.000              12.977    0.015                         0
glms.lvm.zostera.2    1.000              12.953    0.038                     1.386
                            Nemertea          Nephtys.cirrosa         
                   Pr(>Dev)      Dev Pr(>Dev)             Dev Pr(>Dev)
glms.lvm.zostera.1                                                    
glms.lvm.zostera.3    1.000    1.013    1.000           0.811    1.000
glms.lvm.zostera.2    1.000    5.479    0.634           1.386    1.000
                   Nephtys.kersivalensis          Nereis.perivisceralis         
                                     Dev Pr(>Dev)                   Dev Pr(>Dev)
glms.lvm.zostera.1                                                              
glms.lvm.zostera.3                     0    1.000                 0.811    1.000
glms.lvm.zostera.2                 1.386    1.000                     0    1.000
                   Nereis.pulsatoria          Nototropis.guttatus          Oligochaeta
                                 Dev Pr(>Dev)                 Dev Pr(>Dev)         Dev
glms.lvm.zostera.1                                                                    
glms.lvm.zostera.3                 0    1.000               4.485    0.751       5.602
glms.lvm.zostera.2             3.251    0.932               0.116    1.000       9.386
                            Paradoneis.harpagonea          Parthenina.interstincta
                   Pr(>Dev)                   Dev Pr(>Dev)                     Dev
glms.lvm.zostera.1                                                                
glms.lvm.zostera.3    0.607                     0    1.000                   0.919
glms.lvm.zostera.2    0.154                 1.386    1.000                   1.662
                            Parvicardium.exiguum          Perinereis.cultrifera         
                   Pr(>Dev)                  Dev Pr(>Dev)                   Dev Pr(>Dev)
glms.lvm.zostera.1                                                                      
glms.lvm.zostera.3    1.000                0.824    1.000                 0.973    1.000
glms.lvm.zostera.2    0.995                0.063    1.000                 2.035    0.992
                   Perioculodes.longimanus          Phoronida          Phyllodoce.sp.
                                       Dev Pr(>Dev)       Dev Pr(>Dev)            Dev
glms.lvm.zostera.1                                                                   
glms.lvm.zostera.3                   2.111    0.995     1.284    1.000              0
glms.lvm.zostera.2                       0    1.000      0.11    1.000              0
                            Platyhelminthes          Platynereis.dumerilii         
                   Pr(>Dev)             Dev Pr(>Dev)                   Dev Pr(>Dev)
glms.lvm.zostera.1                                                                 
glms.lvm.zostera.3    1.000           1.372    1.000                 1.257    1.000
glms.lvm.zostera.2    1.000           2.602    0.984                 0.374    1.000
                   Polititapes.aureus          Polychaeta.larvae         
                                  Dev Pr(>Dev)               Dev Pr(>Dev)
glms.lvm.zostera.1                                                       
glms.lvm.zostera.3              0.751    1.000                 0    1.000
glms.lvm.zostera.2              6.933    0.404                 0    1.000
                   Polydora.ciliata          Polygordius.neapolitanus         
                                Dev Pr(>Dev)                      Dev Pr(>Dev)
glms.lvm.zostera.1                                                            
glms.lvm.zostera.3             13.8    0.012                        0    1.000
glms.lvm.zostera.2           12.416    0.045                        0    1.000
                   Prionospio.cirrifera          Protodorvillea.kefersteini         
                                    Dev Pr(>Dev)                        Dev Pr(>Dev)
glms.lvm.zostera.1                                                                  
glms.lvm.zostera.3               28.158    0.001                      7.725    0.294
glms.lvm.zostera.2                4.922    0.749                      4.879    0.749
                   Pseudocuma.longicorne          Rissoa.membranacea         
                                     Dev Pr(>Dev)                Dev Pr(>Dev)
glms.lvm.zostera.1                                                           
glms.lvm.zostera.3                 0.236    1.000              1.543    0.998
glms.lvm.zostera.2                 1.386    1.000              1.019    1.000
                   Rissoa.splendida          Salvatoria.clavata         
                                Dev Pr(>Dev)                Dev Pr(>Dev)
glms.lvm.zostera.1                                                      
glms.lvm.zostera.3            5.569    0.607             15.955    0.008
glms.lvm.zostera.2                0    1.000                  0    1.000
                   Schistomeringos.rudolphi          Sphaerosyllis.hystrix         
                                        Dev Pr(>Dev)                   Dev Pr(>Dev)
glms.lvm.zostera.1                                                                 
glms.lvm.zostera.3                    2.389    0.982                 0.023    1.000
glms.lvm.zostera.2                    8.799    0.193                 4.024    0.863
                   Spio.filicornis          Spisula.subtruncata         
                               Dev Pr(>Dev)                 Dev Pr(>Dev)
glms.lvm.zostera.1                                                      
glms.lvm.zostera.3           6.523    0.435                   0    1.000
glms.lvm.zostera.2           0.246    1.000                   0    1.000
                   Stenosoma.capito          Syllis.gracilis          Syllis.hyalina
                                Dev Pr(>Dev)             Dev Pr(>Dev)            Dev
glms.lvm.zostera.1                                                                  
glms.lvm.zostera.3            2.178    0.994           4.755    0.707          2.507
glms.lvm.zostera.2            6.661    0.472          17.831    0.008              0
                            Tellina.tenuis          Thracia.phaseolina         
                   Pr(>Dev)            Dev Pr(>Dev)                Dev Pr(>Dev)
glms.lvm.zostera.1                                                             
glms.lvm.zostera.3    0.979          1.622    0.997              0.811    1.000
glms.lvm.zostera.2    1.000          1.386    1.000                  0    1.000
                   Tricolia.pullus          Tritia.neritea          Tritia.reticulata
                               Dev Pr(>Dev)            Dev Pr(>Dev)               Dev
glms.lvm.zostera.1                                                                   
glms.lvm.zostera.3           5.332    0.629          0.632    1.000                 0
glms.lvm.zostera.2            1.38    1.000          3.479    0.917             8.301
                            Turbellaria          Upogebia.pusilla         
                   Pr(>Dev)         Dev Pr(>Dev)              Dev Pr(>Dev)
glms.lvm.zostera.1                                                        
glms.lvm.zostera.3    1.000       1.392    0.999            5.769    0.566
glms.lvm.zostera.2    0.239       1.125    1.000                0    1.000
Arguments:
 Test statistics calculated assuming uncorrelated response (for faster computation) 
P-value calculated using 999 resampling iterations via PIT-trap resampling (to account for correlation in testing.

Well this is tough to interpret.. Multivariate test table’s Dev is decrement from upper model, so each p-value indicates the difference between the model and upper one is statistically significant… But no info on which model represents the species matrix best.

I’ll go with the model with the lowest AIC, since there is no other objective criterion to go with.. This happens to be model 2 (groups = stations). Exactly the same result as from the classical methods.

glms.lvm.zostera.1$AICsum
[1] 6804.496
glms.lvm.zostera.2$AICsum
[1] 6661.507
glms.lvm.zostera.3$AICsum
[1] 6730.346
manyGLM by environmental parameters

Now, let’s try to see a different thing - which environmental parameters best describe the species response.
I’m going to use the PCA-filtered environmental data - it’s still going to be a slog, with 7 potential predictors..
First, construct the formula for the model - will do it separately in case I need to update it later, etc.
NB there is year here - I want to try with it first!! And I don’t want the Secchi depth - it has NAs for Vromos.

(formula.env.glms.zostera <- formula(paste("zoo.mvabnd.zostera ~",
                                           paste(env.zostera %>% select(-c(station, secchi)) %>% names(), collapse = "+")))
)
zoo.mvabnd.zostera ~ year + Ntotal + chl_a + LUSI + TOM + moisture_content + 
    mean_grain_size + sand + silt_clay + shoot_count + ag_biomass_wet + 
    bg_biomass_wet

Fit the GLMs - including all environmental parameters - to the zostera abundance data.

env.glms.zostera <- manyglm(formula.env.glms.zostera,
                            data = env.zostera,
                            family = "negative.binomial")

Explore the fit (residuals, diagnostic plots, etc.).

## residuals vs fitted values
plot(env.glms.zostera)

## all traditional (g)lm diagnostic plots
plot.manyglm(env.glms.zostera, which = 1:3)

# ### source mvabund GLM plotting functions modified to use a grey palette - I just can't redo these plots on my own, the function is doing too complicated things internally to scale the x and y axes
# source(here(functions.dir, "default.plot.manyglm_grey.R"))
# source(here(functions.dir, "plot.manyglm_grey.R"))
# 
# par(mfrow = c(2,2))
# lapply(1:3, function(i) plot.manyglm.grey(glms.lvm.zostera, which = i, sub.caption = ""))
# par(mfrow = c(1, 1))

Well, it’s good enough if you ask me (still the kinda strange “line” at lin.pred = -6; otherwise residuals are random enough).

Save the model!

write_rds(env.glms.zostera, 
          here(save.dir, "glms_env_zostera.RDS"))

Before going off and running an ANOVA to check which predictors best explain the species abundance patterns, I’ll try to reduce the model a little - it might even improve the fit, not to mention the run time.

top.env.glm.red.zostera <- evaluate_glms_env(env.glms.zostera)
the condition has length > 1 and only the first element will be used
[1] "Best model:  zoo.mvabnd.zostera ~ Ntotal + sand + shoot_count + ag_biomass_wet +     bg_biomass_wet"

Check its fit.

## residuals vs fitted values
plot(top.env.glm.red.zostera)

## all traditional (g)lm diagnostic plots
plot.manyglm(top.env.glm.red.zostera, which = 1:3)

I think it’s fine; might even be better than the full model.. Save it, too.

write_rds(top.env.glm.red.zostera, 
          here(save.dir, "glms_top_env_red_zostera.RDS"))

Run ANOVA on this model.

(top.env.glm.red.zostera.aov <- anova.manyglm(top.env.glm.red.zostera,
                                              test = "LR", p.uni = "adjusted", 
                                              nBoot = 999, ## limit the number of permutations for a shorter run time   
                                              show.time = "all") 
)
Resampling begins for test 1.
    Resampling run 0 finished. Time elapsed: 0.00 minutes...
    Resampling run 100 finished. Time elapsed: 0.13 minutes...
    Resampling run 200 finished. Time elapsed: 0.26 minutes...
    Resampling run 300 finished. Time elapsed: 0.39 minutes...
    Resampling run 400 finished. Time elapsed: 0.53 minutes...
    Resampling run 500 finished. Time elapsed: 0.66 minutes...
    Resampling run 600 finished. Time elapsed: 0.79 minutes...
    Resampling run 700 finished. Time elapsed: 0.92 minutes...
    Resampling run 800 finished. Time elapsed: 1.05 minutes...
    Resampling run 900 finished. Time elapsed: 1.18 minutes...
Resampling begins for test 2.
    Resampling run 0 finished. Time elapsed: 0.00 minutes...
    Resampling run 100 finished. Time elapsed: 0.14 minutes...
    Resampling run 200 finished. Time elapsed: 0.28 minutes...
    Resampling run 300 finished. Time elapsed: 0.43 minutes...
    Resampling run 400 finished. Time elapsed: 0.57 minutes...
    Resampling run 500 finished. Time elapsed: 0.71 minutes...
    Resampling run 600 finished. Time elapsed: 0.87 minutes...
    Resampling run 700 finished. Time elapsed: 1.02 minutes...
    Resampling run 800 finished. Time elapsed: 1.16 minutes...
    Resampling run 900 finished. Time elapsed: 1.31 minutes...
Resampling begins for test 3.
    Resampling run 0 finished. Time elapsed: 0.00 minutes...
    Resampling run 100 finished. Time elapsed: 0.15 minutes...
    Resampling run 200 finished. Time elapsed: 0.29 minutes...
    Resampling run 300 finished. Time elapsed: 0.43 minutes...
    Resampling run 400 finished. Time elapsed: 0.56 minutes...
    Resampling run 500 finished. Time elapsed: 0.70 minutes...
    Resampling run 600 finished. Time elapsed: 0.85 minutes...
    Resampling run 700 finished. Time elapsed: 0.99 minutes...
    Resampling run 800 finished. Time elapsed: 1.13 minutes...
    Resampling run 900 finished. Time elapsed: 1.27 minutes...
Resampling begins for test 4.
    Resampling run 0 finished. Time elapsed: 0.00 minutes...
    Resampling run 100 finished. Time elapsed: 0.14 minutes...
    Resampling run 200 finished. Time elapsed: 0.27 minutes...
    Resampling run 300 finished. Time elapsed: 0.42 minutes...
    Resampling run 400 finished. Time elapsed: 0.55 minutes...
    Resampling run 500 finished. Time elapsed: 0.69 minutes...
    Resampling run 600 finished. Time elapsed: 0.83 minutes...
    Resampling run 700 finished. Time elapsed: 0.96 minutes...
    Resampling run 800 finished. Time elapsed: 1.09 minutes...
    Resampling run 900 finished. Time elapsed: 1.22 minutes...
Resampling begins for test 5.
    Resampling run 0 finished. Time elapsed: 0.00 minutes...
    Resampling run 100 finished. Time elapsed: 0.12 minutes...
    Resampling run 200 finished. Time elapsed: 0.25 minutes...
    Resampling run 300 finished. Time elapsed: 0.37 minutes...
    Resampling run 400 finished. Time elapsed: 0.50 minutes...
    Resampling run 500 finished. Time elapsed: 0.62 minutes...
    Resampling run 600 finished. Time elapsed: 0.74 minutes...
    Resampling run 700 finished. Time elapsed: 0.86 minutes...
    Resampling run 800 finished. Time elapsed: 0.98 minutes...
    Resampling run 900 finished. Time elapsed: 1.11 minutes...
Time elapsed: 0 hr 6 min 45 sec
Analysis of Deviance Table

Model: manyglm(formula = zoo.mvabnd.zostera ~ Ntotal + sand + shoot_count + 
Model:     ag_biomass_wet + bg_biomass_wet, family = "negative.binomial", 
Model:     data = env.zostera)

Multivariate test:
               Res.Df Df.diff   Dev Pr(>Dev)    
(Intercept)        31                           
Ntotal             30       1 299.7    0.001 ***
sand               29       1 272.1    0.001 ***
shoot_count        28       1 355.3    0.001 ***
ag_biomass_wet     27       1 235.2    0.001 ***
bg_biomass_wet     26       1 424.9    0.001 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Univariate Tests:
               Abra.alba          Abra.sp.          Actiniaria          Alitta.succinea
                     Dev Pr(>Dev)      Dev Pr(>Dev)        Dev Pr(>Dev)             Dev
(Intercept)                                                                            
Ntotal             6.177    0.545    4.157    0.945      1.004    1.000          19.751
sand               19.42    0.004        0    1.000      0.412    1.000           0.204
shoot_count        0.506    1.000    0.002    1.000      2.581    0.999           1.336
                        Ampelisca.diadema          Amphibalanus.improvisus         
               Pr(>Dev)               Dev Pr(>Dev)                     Dev Pr(>Dev)
(Intercept)                                                                        
Ntotal            0.003             5.846    0.578                  10.874    0.057
sand              1.000            25.503    0.002                   1.185    1.000
shoot_count       1.000            27.113    0.001                   0.224    1.000
               Ampithoe.sp.          Anadara.kagoshimensis          Apherusa.bispinosa
                        Dev Pr(>Dev)                   Dev Pr(>Dev)                Dev
(Intercept)                                                                           
Ntotal               10.408    0.080                 1.004    0.999               0.83
sand                  1.162    1.000                 0.381    1.000              3.329
shoot_count            0.23    1.000                 2.765    0.995                  0
                        Apseudopsis.ostroumovi          Bittium.reticulatum         
               Pr(>Dev)                    Dev Pr(>Dev)                 Dev Pr(>Dev)
(Intercept)                                                                         
Ntotal            1.000                  5.466    0.634               1.145    0.999
sand              0.981                  5.211    0.802               0.291    1.000
shoot_count       1.000                 10.604    0.169              18.053    0.006
               Brachynotus.sexdentatus          Capitella.capitata         
                                   Dev Pr(>Dev)                Dev Pr(>Dev)
(Intercept)                                                                
Ntotal                           0.004    1.000              1.871    0.998
sand                             0.202    1.000              1.595    0.999
shoot_count                      0.445    1.000              15.66    0.019
               Capitella.minima          Chamelea.gallina          Chironomidae.larvae
                            Dev Pr(>Dev)              Dev Pr(>Dev)                 Dev
(Intercept)                                                                           
Ntotal                    1.126    0.999            0.789    1.000               9.648
sand                      0.223    1.000            3.252    0.986                   0
shoot_count              20.087    0.003           12.142    0.098               0.001
                        Cumella.limicola          Cumella.pygmaea         
               Pr(>Dev)              Dev Pr(>Dev)             Dev Pr(>Dev)
(Intercept)                                                               
Ntotal            0.162            0.501    1.000             2.1    0.996
sand              1.000            2.908    0.992            7.78    0.433
shoot_count       1.000            3.986    0.934           0.001    1.000
               Cytharella.costulata          Diogenes.pugilator          Eteone.flava
                                Dev Pr(>Dev)                Dev Pr(>Dev)          Dev
(Intercept)                                                                          
Ntotal                        0.849    1.000              0.003    1.000        4.157
sand                          0.163    1.000              0.317    1.000            0
shoot_count                    0.48    1.000              6.108    0.672        0.002
                        Eunice.vittata          Eurydice.dollfusi         
               Pr(>Dev)            Dev Pr(>Dev)               Dev Pr(>Dev)
(Intercept)                                                               
Ntotal            0.940          3.083    0.990               2.1    0.996
sand              1.000          3.191    0.988             7.638    0.449
shoot_count       1.000          0.665    1.000             0.142    1.000
               Exogone.naidina          Gastrosaccus.sanctus         
                           Dev Pr(>Dev)                  Dev Pr(>Dev)
(Intercept)                                                          
Ntotal                   7.771    0.381                 0.83    1.000
sand                     3.266    0.986                3.329    0.976
shoot_count              0.698    1.000                    0    1.000
               Genetyllis.tuberculata          Glycera.sp.          Glycera.tridactyla
                                  Dev Pr(>Dev)         Dev Pr(>Dev)                Dev
(Intercept)                                                                           
Ntotal                          1.232    0.999       1.097    0.999              0.066
sand                            6.164    0.679       4.521    0.887              2.045
shoot_count                     3.149    0.976       0.675    1.000              8.534
                        Glycera.unicornis          Harmothoe.imbricata         
               Pr(>Dev)               Dev Pr(>Dev)                 Dev Pr(>Dev)
(Intercept)                                                                    
Ntotal            1.000             1.004    1.000               0.915    1.000
sand              0.999             0.381    1.000               6.699    0.595
shoot_count       0.342             2.765    0.996              10.277    0.192
               Harmothoe.reticulata          Heteromastus.filiformis          Hirudinea
                                Dev Pr(>Dev)                     Dev Pr(>Dev)       Dev
(Intercept)                                                                            
Ntotal                        2.036    0.997                   2.133    0.996         0
sand                          8.582    0.320                   4.357    0.912     0.091
shoot_count                   0.077    1.000                   1.732    1.000     0.014
                        Hydrobia.acuta          Hydrobia.sp.          Iphinoe.tenella
               Pr(>Dev)            Dev Pr(>Dev)          Dev Pr(>Dev)             Dev
(Intercept)                                                                          
Ntotal            1.000          1.425    0.999        1.301    0.999           0.144
sand              1.000          0.408    1.000        0.215    1.000           3.241
shoot_count       1.000          2.507    0.999        0.013    1.000           0.005
                        Kellia.suborbicularis          Lagis.koreni         
               Pr(>Dev)                   Dev Pr(>Dev)          Dev Pr(>Dev)
(Intercept)                                                                 
Ntotal            1.000                 2.726    0.990            0    1.000
sand              0.986                 1.702    0.999        2.559    0.996
shoot_count       1.000                 8.058    0.409       11.219    0.140
               Leiochone.leiopygos          Lentidium.mediterraneum         
                               Dev Pr(>Dev)                     Dev Pr(>Dev)
(Intercept)                                                                 
Ntotal                       2.493    0.992                   1.659    0.999
sand                          1.08    1.000                   6.526    0.645
shoot_count                  7.538    0.473                   0.131    1.000
               Lepidochitona.cinerea          Loripes.orbiculatus         
                                 Dev Pr(>Dev)                 Dev Pr(>Dev)
(Intercept)                                                               
Ntotal                          0.83    1.000               1.634    0.999
sand                           3.215    0.988               1.236    1.000
shoot_count                    0.113    1.000              22.136    0.001
               Lucinella.divaricata          Magelona.papillicornis         
                                Dev Pr(>Dev)                    Dev Pr(>Dev)
(Intercept)                                                                 
Ntotal                        2.519    0.992                   0.83    1.000
sand                          0.005    1.000                  3.215    0.988
shoot_count                   3.884    0.942                  0.113    1.000
               Maldane.glebifex          Melinna.palmata         
                            Dev Pr(>Dev)             Dev Pr(>Dev)
(Intercept)                                                      
Ntotal                    1.004    0.999           3.974    0.966
sand                      0.412    1.000           1.826    0.999
shoot_count               2.581    0.999            5.31    0.810
               Microdeutopus.gryllotalpa          Micromaldane.ornithochaeta         
                                     Dev Pr(>Dev)                        Dev Pr(>Dev)
(Intercept)                                                                          
Ntotal                             5.334    0.664                      4.195    0.900
sand                               1.148    1.000                      6.449    0.655
shoot_count                         3.03    0.981                          0    1.000
               Micronephthys.stammeri          Microphthalmus.fragilis         
                                  Dev Pr(>Dev)                     Dev Pr(>Dev)
(Intercept)                                                                    
Ntotal                          3.828    0.970                    0.03    1.000
sand                            0.614    1.000                   1.905    0.999
shoot_count                     1.079    1.000                   2.619    0.998
               Microphthalmus.sp.          Monocorophium.acherusicum         
                              Dev Pr(>Dev)                       Dev Pr(>Dev)
(Intercept)                                                                  
Ntotal                      1.497    0.999                    14.561    0.019
sand                        0.028    1.000                     0.234    1.000
shoot_count                 4.309    0.932                    18.824    0.005
               Mytilaster.lineatus          Mytilus.galloprovincialis          Nemertea
                               Dev Pr(>Dev)                       Dev Pr(>Dev)      Dev
(Intercept)                                                                            
Ntotal                       15.75    0.012                     1.004    0.999    0.617
sand                         1.073    1.000                     0.381    1.000    0.254
shoot_count                  5.489    0.792                     2.765    0.995      9.1
                        Nephtys.cirrosa          Nephtys.kersivalensis         
               Pr(>Dev)             Dev Pr(>Dev)                   Dev Pr(>Dev)
(Intercept)                                                                    
Ntotal            1.000           0.458    1.000                 1.004    1.000
sand              1.000           0.059    1.000                 0.381    1.000
shoot_count       0.288           1.444    1.000                 2.765    0.996
               Nereis.perivisceralis          Nereis.pulsatoria         
                                 Dev Pr(>Dev)               Dev Pr(>Dev)
(Intercept)                                                             
Ntotal                          0.83    1.000             2.909    0.990
sand                           3.329    0.976             0.077    1.000
shoot_count                        0    1.000             0.002    1.000
               Nototropis.guttatus          Oligochaeta          Paradoneis.harpagonea
                               Dev Pr(>Dev)         Dev Pr(>Dev)                   Dev
(Intercept)                                                                           
Ntotal                       4.526    0.882       5.007    0.722                 1.004
sand                         1.555    0.999       1.836    0.999                 0.412
shoot_count                  4.117    0.932      12.359    0.089                 2.581
                        Parthenina.interstincta          Parvicardium.exiguum         
               Pr(>Dev)                     Dev Pr(>Dev)                  Dev Pr(>Dev)
(Intercept)                                                                           
Ntotal            1.000                   1.009    0.999                2.023    0.997
sand              1.000                   0.001    1.000                0.537    1.000
shoot_count       0.999                  10.718    0.169                2.433    0.999
               Perinereis.cultrifera          Perioculodes.longimanus          Phoronida
                                 Dev Pr(>Dev)                     Dev Pr(>Dev)       Dev
(Intercept)                     <NA>     <NA>                    <NA>     <NA>      <NA>
Ntotal                         2.475    0.992                   0.055    1.000     0.004
sand                           1.989    0.999                   0.003    1.000     2.218
shoot_count                     0.04    1.000                   5.602    0.769      4.34
                        Phyllodoce.sp.          Platyhelminthes         
               Pr(>Dev)            Dev Pr(>Dev)             Dev Pr(>Dev)
(Intercept)        <NA>           <NA>     <NA>            <NA>     <NA>
Ntotal            1.000          4.157    0.940           1.998    0.997
sand              0.998              0    1.000               0    1.000
shoot_count       0.928          0.002    1.000           0.742    1.000
               Platynereis.dumerilii          Polititapes.aureus         
                                 Dev Pr(>Dev)                Dev Pr(>Dev)
(Intercept)                     <NA>     <NA>               <NA>     <NA>
Ntotal                         1.236    0.999              0.241    1.000
sand                           0.216    1.000              6.606    0.624
shoot_count                     6.46    0.620              1.073    1.000
               Polychaeta.larvae          Polydora.ciliata         
                             Dev Pr(>Dev)              Dev Pr(>Dev)
(Intercept)                 <NA>     <NA>             <NA>     <NA>
Ntotal                     4.157    0.937           25.833    0.001
sand                           0    1.000           10.787    0.131
shoot_count                0.002    1.000            4.281    0.932
               Polygordius.neapolitanus          Prionospio.cirrifera         
                                    Dev Pr(>Dev)                  Dev Pr(>Dev)
(Intercept)                        <NA>     <NA>                 <NA>     <NA>
Ntotal                            4.157    0.937                3.887    0.967
sand                                  0    1.000               48.848    0.001
shoot_count                       0.002    1.000                0.005    1.000
               Protodorvillea.kefersteini          Pseudocuma.longicorne         
                                      Dev Pr(>Dev)                   Dev Pr(>Dev)
(Intercept)                          <NA>     <NA>                  <NA>     <NA>
Ntotal                              5.159    0.708                 0.884    1.000
sand                                0.994    1.000                 2.017    0.999
shoot_count                          0.73    1.000                 0.192    1.000
               Rissoa.membranacea          Rissoa.splendida          Salvatoria.clavata
                              Dev Pr(>Dev)              Dev Pr(>Dev)                Dev
(Intercept)                  <NA>     <NA>             <NA>     <NA>               <NA>
Ntotal                      2.146    0.996            0.416    1.000              1.798
sand                        3.924    0.953            3.515    0.964              2.994
shoot_count                 0.204    1.000             1.17    1.000              0.118
                        Schistomeringos.rudolphi          Sphaerosyllis.hystrix         
               Pr(>Dev)                      Dev Pr(>Dev)                   Dev Pr(>Dev)
(Intercept)        <NA>                     <NA>     <NA>                  <NA>     <NA>
Ntotal            0.999                    1.251    0.999                 0.109    1.000
sand              0.991                    1.657    0.999                 0.151    1.000
shoot_count       1.000                     9.19    0.284                10.018    0.223
               Spio.filicornis          Spisula.subtruncata          Stenosoma.capito
                           Dev Pr(>Dev)                 Dev Pr(>Dev)              Dev
(Intercept)               <NA>     <NA>                <NA>     <NA>             <NA>
Ntotal                  17.283    0.007               0.014    1.000             1.53
sand                     0.075    1.000               0.081    1.000            4.409
shoot_count              5.161    0.847                3.58    0.961             0.02
                        Syllis.gracilis          Syllis.hyalina          Tellina.tenuis
               Pr(>Dev)             Dev Pr(>Dev)            Dev Pr(>Dev)            Dev
(Intercept)        <NA>            <NA>     <NA>           <NA>     <NA>           <NA>
Ntotal            0.999           3.343    0.986          4.551    0.882          1.144
sand              0.901           0.432    1.000              0    1.000          1.096
shoot_count       1.000           1.132    1.000          0.001    1.000          2.189
                        Thracia.phaseolina          Tricolia.pullus         
               Pr(>Dev)                Dev Pr(>Dev)             Dev Pr(>Dev)
(Intercept)        <NA>               <NA>     <NA>            <NA>     <NA>
Ntotal            0.999               0.83    1.000           3.903    0.967
sand              1.000              3.329    0.981           0.445    1.000
shoot_count       0.999                  0    1.000           0.012    1.000
               Tritia.neritea          Tritia.reticulata          Turbellaria         
                          Dev Pr(>Dev)               Dev Pr(>Dev)         Dev Pr(>Dev)
(Intercept)              <NA>     <NA>              <NA>     <NA>        <NA>     <NA>
Ntotal                  0.972    1.000             0.049    1.000        0.01    1.000
sand                    0.698    1.000             5.174    0.808       0.763    1.000
shoot_count             0.444    1.000             0.182    1.000       0.158    1.000
               Upogebia.pusilla         
                            Dev Pr(>Dev)
(Intercept)                <NA>     <NA>
Ntotal                   10.023    0.128
sand                          0    1.000
shoot_count               0.001    1.000
 [ reached getOption("max.print") -- omitted 2 rows ]
Arguments:
 Test statistics calculated assuming uncorrelated response (for faster computation) 
P-value calculated using 999 resampling iterations via PIT-trap resampling (to account for correlation in testing.

Nice, all terms are significant now! Again, as with the sand samples, there is one eutrophication term + one sediment composition + seagrass parameters. Seems reasonable enough.

Save this ANOVA (takes too long to run anew).

write_rds(top.env.glm.red.zostera.aov, 
          here(save.dir, "glms_top_env_red_zostera_anova.RDS"))

Get the taxa with the highest contributions to the tested pattern (here - species most affected by changes in water/environmental quality parameters).

## get the top contributing species for the environmental parameter zostera GLMs 
(top.sp.glms.env.red.zostera <- top_n_sp_glm(top.env.glm.red.zostera.aov, tot.dev.expl = 0.75)
)
[1] "Total deviance explained: 0.771"
          Polydora.ciliata            Alitta.succinea            Spio.filicornis 
                 25.833258                  19.750751                  17.282878 
       Mytilaster.lineatus  Monocorophium.acherusicum    Amphibalanus.improvisus 
                 15.750298                  14.561059                  10.874348 
              Ampithoe.sp.           Upogebia.pusilla        Chironomidae.larvae 
                 10.407890                  10.022548                   9.647785 
           Exogone.naidina                  Abra.alba          Ampelisca.diadema 
                  7.770666                   6.177181                   5.846268 
    Apseudopsis.ostroumovi  Microdeutopus.gryllotalpa Protodorvillea.kefersteini 
                  5.466183                   5.334367                   5.159364 
               Oligochaeta             Syllis.hyalina        Nototropis.guttatus 
                  5.007334                   4.551098                   4.525633 
Micromaldane.ornithochaeta          Polychaeta.larvae   Polygordius.neapolitanus 
                  4.195233                   4.157056                   4.157056 
              Eteone.flava             Phyllodoce.sp.                   Abra.sp. 
                  4.157056                   4.157056                   4.157056 
           Melinna.palmata            Tricolia.pullus       Prionospio.cirrifera 
                  3.974488                   3.902948                   3.886516 
    Micronephthys.stammeri            Syllis.gracilis             Eunice.vittata 
                  3.827638                   3.343254                   3.082611 
## unfortunately, mvabund likes to rename my species when converting the data to matrix (no spaces in names), and since I'm going to look them up in my initial untransformed count data, I have to change them back..   DON'T BE IN A HURRY TO DO THAT IF YOU WANT TO SUBSET THE ORIGINAL MATRIX BEFORE RUNNING TRAITGLM 
names(top.sp.glms.env.red.zostera) <- names(top.sp.glms.env.red.zostera) %>% 
  str_replace(pattern = "\\.", replacement = " ")

I’m going to plot these top contributing species, but I’m not using the plot. At least this time it’s more manageable, but still not presentable enough..

## get the species and their abundances from the original count data, and transform them to long format
(abnd.top.sp.glms.env.red.zostera <- zoo.abnd.zostera %>% 
   select(station, names(top.sp.glms.env.red.zostera)) %>% 
   gather(key = "species", value = "count", -station) %>% 
   ## turn species into a factor, or you'll be very very sorry later, when they're out of order on the plot. NB need to be in REVERSE order, because ggplot plots from bottom to top, and I want the top-contributing species on top. 
   mutate(species = factor(species, levels = rev(names(top.sp.glms.env.red.zostera)))) %>% 
   ## add clusters from LVM as a column
   mutate(group = case_when(station == "Poda" ~ 1, 
                            station == "Otmanli" ~ 2, 
                            station == "Vromos" ~ 3, 
                            station == "Gradina" ~ 4, 
                            station == "Ropotamo" ~ 5))
)
(plot.top.sp.glms.env.red.zostera <- plot_top_n(abnd.top.sp.glms.env.red.zostera,
                                         mapping = aes(x = species, y = log_y_min(count), colour = factor(group)),
                                         labs.legend = unique(abnd.top.sp.glms.env.red.zostera$group),
                                         lab.y = "Abundance (log(y/min + 1))",
                                         palette = "Set2"
                                        ) + 
    theme(legend.position = "top")
)

Extract the taxon information (univariate tests) from the model ANOVA to present as a table (probably better than this plot, although it’s informative).

## extract the univariate test coefficients (LR) from the environmental model ANOVA. NB keep the row names when converting the matrix to tibble! 
table.top.sp.glms.env.red.zostera <- as_tibble(top.env.glm.red.zostera.aov$uni.test, rownames = "var")
## fix the species names - remove first dor  
names(table.top.sp.glms.env.red.zostera) <- names(table.top.sp.glms.env.red.zostera) %>% 
  str_replace(pattern = "\\.", replacement = " ")
## subset only the top species (explaining ~75% of the dataset variation)
table.top.sp.glms.env.red.zostera <- table.top.sp.glms.env.red.zostera %>% 
  select(var, names(top.sp.glms.env.red.zostera))
## transpose, because a table with 50 columns is just unreadable
(table.top.sp.glms.env.red.zostera <- table.top.sp.glms.env.red.zostera %>%
    gather(key = species, value = value, -var) %>% 
    spread(key = var, value = value) %>% 
    ## arrange as before (terms in the order they appear in the model, and by descending value of the LR for the first model term - here, PO4). Also get rid of the intercept (it's all-NA anyway).
    select(species, Ntotal, sand, shoot_count, ag_biomass_wet, bg_biomass_wet) %>%
    arrange(desc(Ntotal)) 
)

Save this to a file - will have to format it as a nice table by hand, unfortunately.

write_csv(table.top.sp.glms.env.red.zostera, 
          here(save.dir, "taxa_contrib_glms_top_env_red_zostera.csv"))

Calculate the percentage contribution of each of these species to each of the model terms (Dev(term) = Sum-of-LR - sum of the LRs for the individual univariate species tests)..

## get the total deviance (Sum-of-LR) for each model term
(dev.terms.top.glms.env.zostera <- as_tibble(top.env.glm.red.zostera.aov$table, rownames = "var") %>%
   ## get rid of unnecessary variables (I only want the deviance value for each term) and intercept term 
   select(var, Dev) %>% 
   filter(var != "(Intercept)") %>% 
   ## transpose 
   gather(variable, value, -var) %>%
   spread(var, value) %>% 
   ## get rid of first column and rearrange columns to match table of deviances of univariate tests for species 
   select(-variable) %>% 
   select(Ntotal, sand, shoot_count, ag_biomass_wet, bg_biomass_wet)
)  
## calculate the proportion contribution of each species to each parameter deviance
prop.top.sp.glms.env.red.zostera <- map2_df(table.top.sp.glms.env.red.zostera %>% select(-species), 
                                            dev.terms.top.glms.env.zostera,
                                            ~.x/.y)
## add back the species 
(prop.top.sp.glms.env.red.zostera <- bind_cols(table.top.sp.glms.env.red.zostera %>% select(species), 
                                               prop.top.sp.glms.env.red.zostera)
)

I’ll do the pseudo-traits analysis - fit single predictive model for all species at all sites, but w/o attempting to explain the different responses using traits - the species ID is used in place of a traits matrix), although I don’t think it will amount to anything useful.
NB only use the top species that exhibited a reaction in the environmental model fit (= the ones accounting for ~75% of the total variability), and only the significant predictors - to improve run times.

sp.response.glms.env.red.zostera <- traitglm(L = mvabund(zoo.abnd.flt.zostera[, names(top.sp.glms.env.red.zostera)]), 
                                             R = as.matrix(env.zostera %>% select(Ntotal, sand, shoot_count, ag_biomass_wet, bg_biomass_wet)), 
                                             method = "manyglm")
No traits matrix entered, so will fit SDMs with different env response for each spp 
sp.response.glms.env.red.zostera$fourth.corner
                                        Ntotal          sand shoot_count ag_biomass_wet
names.L.Abra.sp.                   -0.47066762  0.8734886154  0.46922359    -0.19993821
names.L.Alitta.succinea             0.97052617  0.9239972975  0.15761977     0.34540391
names.L.Ampelisca.diadema           0.07926714  0.4982502059  0.08427469     0.04139468
names.L.Amphibalanus.improvisus     0.01579908  0.1367386026  0.02102261    -0.02672181
names.L.Ampithoe.sp.               -0.23185028  0.9766780527 -0.86628249    -0.74571356
names.L.Apseudopsis.ostroumovi      1.64548321 -1.0408187107 -1.81840977     0.56715226
names.L.Chironomidae.larvae         1.31227261  0.1002162364  0.12598021     0.05010550
names.L.Eteone.flava               -0.47066762  0.8734886147  0.46922359    -0.19993821
names.L.Eunice.vittata             -0.80681453 -1.1651097143  0.87652213     0.87742696
names.L.Exogone.naidina            -2.71929348 -1.2204528999  0.50458742     0.72444467
names.L.Melinna.palmata            -0.60638932  0.1355595122  0.47942801    -0.75972197
names.L.Microdeutopus.gryllotalpa  -0.06793176  0.1548066634  0.05529672     0.15492252
names.L.Micromaldane.ornithochaeta -0.03794287  1.1454709967  0.21794177    -0.18913046
names.L.Micronephthys.stammeri     -0.27494238 -0.3866591307  0.52525177     1.09138609
names.L.Monocorophium.acherusicum  -0.17196470  0.2856739339  0.13559306    -0.02596581
names.L.Mytilaster.lineatus        -0.12863711  0.0415408498 -0.21351554     0.13096055
names.L.Nototropis.guttatus        -3.39299319 -2.6671597928  1.95831019     2.81907411
names.L.Oligochaeta                 0.24580986  0.0008031048 -0.27535910     0.05999869
names.L.Phyllodoce.sp.             -0.47066762  0.8734886150  0.46922359    -0.19993821
names.L.Polychaeta.larvae          -0.47066762  0.8734886136  0.46922359    -0.19993820
names.L.Polydora.ciliata            0.08423213  0.0097291405  0.15937837     0.02005751
names.L.Polygordius.neapolitanus   -0.47066762  0.8734886143  0.46922359    -0.19993821
names.L.Prionospio.cirrifera        0.88939049 -0.8247531556 -0.04010420    -0.33490099
names.L.Protodorvillea.kefersteini -2.59810569 -2.3545060528  0.75998659     2.29012099
names.L.Spio.filicornis            -0.38562919  0.2369199100  0.06576463    -0.07758304
names.L.Syllis.gracilis             0.70617192 -1.4267780844 -1.03624608     0.23992203
names.L.Syllis.hyalina              1.41675539  0.0868009271  0.13451699     0.04413407
names.L.Tricolia.pullus            -0.66341187 -2.5031380589 -0.53076627     1.42443911
names.L.Upogebia.pusilla            1.37595789  0.0920536483  0.13121625     0.04647257
                                   bg_biomass_wet
names.L.Abra.sp.                      -0.25357886
names.L.Alitta.succinea               -0.76895635
names.L.Ampelisca.diadema              0.18259939
names.L.Amphibalanus.improvisus       -0.23201790
names.L.Ampithoe.sp.                   0.03055559
names.L.Apseudopsis.ostroumovi         1.74812763
names.L.Chironomidae.larvae            1.03836845
names.L.Eteone.flava                  -0.25357886
names.L.Eunice.vittata                 0.52390238
names.L.Exogone.naidina                0.09265243
names.L.Melinna.palmata               -1.53484185
names.L.Microdeutopus.gryllotalpa      0.19540154
names.L.Micromaldane.ornithochaeta     0.50432844
names.L.Micronephthys.stammeri         0.19869790
names.L.Monocorophium.acherusicum      0.03209065
names.L.Mytilaster.lineatus            0.41368623
names.L.Nototropis.guttatus            1.74403783
names.L.Oligochaeta                    0.37862412
names.L.Phyllodoce.sp.                -0.25357886
names.L.Polychaeta.larvae             -0.25357886
names.L.Polydora.ciliata              -0.18809997
names.L.Polygordius.neapolitanus      -0.25357886
names.L.Prionospio.cirrifera          -0.11604329
names.L.Protodorvillea.kefersteini     1.48926441
names.L.Spio.filicornis               -0.32857846
names.L.Syllis.gracilis                1.78601308
names.L.Syllis.hyalina                 1.10641092
names.L.Tricolia.pullus                2.08730622
names.L.Upogebia.pusilla               1.07984888
# plot this 
a.z <- max(abs(sp.response.glms.env.red.zostera$fourth.corner))
colort <- colorRampPalette(c("blue","white","red")) 
plot.spp.z <- lattice::levelplot(t(as.matrix(sp.response.glms.env.red.zostera$fourth.corner)), xlab = "Environmental Variables",
                     ylab = "Species", col.regions = colort(100), at = seq(-a.z, a.z, length = 100),
                     scales = list(x = list(rot = 45)))
print(plot.spp.z)

Here at least the directions are a little more coherent than the environmental parameters for the sand stations (seagrass biomasses more or less in the same direction, etc.). The below-ground biomass exerts more pronounced influence on the specific abundances - normal, since most of these are infauna.

LS0tCnRpdGxlOiAiTXVsdGl2YXJpYXRlIGFuYWx5c2VzIG9mIGNvbW11bml0eSBzdHJ1Y3R1cmUgKG1vZGVsaW5nKSIKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpUaGlzIG5vdGVib29rIGNvbnRhaW5zIGFsbCBtdWx0aXZhcmlhdGUgYW5hbHlzZXMgb2Ygem9vYmVudGhpYyBjb21tdW5pdHkgc3RydWN0dXJlIHVzaW5nIHRoZSBuZXcsIG5lYXJseSB1bmhlYXJkLW9mIG1vZGVsaW5nIG1ldGhvZHM6IHBhY2thZ2VzIG12YWJ1bmQsIGJvcmFsLiAgCkFnYWluLCB0byBtYWtlIGl0IHNlbGYtY29udGFpbmVkLCB0aGVyZSB3aWxsIGJlIHRoZSBzYW1lIHJlcGV0aXRpdmUgc2V0dXAvZGF0YSBpbXBvcnQvcHJlcGFyYXRpb24gcGFydC4gIAoKKioqICAKClNldHVwIQpgYGB7ciBzZXR1cCwgaW5jbHVkZSA9IEZBTFNFfQpsaWJyYXJ5KGtuaXRyKQoKa25pdF9ob29rcyRzZXQoc21hbGwubWFyID0gZnVuY3Rpb24oYmVmb3JlLCBvcHRpb25zLCBlbnZpcikgewogICAgaWYgKGJlZm9yZSkgcGFyKG1hciA9IGMoMiwgMiwgLjEsIDIpKSAgIyBzbWFsbGVyIG1hcmdpbiBvbiB0b3AKfSkKCiMjIHNldCB0aGUgd29ya2luZyBkaXJlY3RvcnkgdG8gb25lIHVwIChhbGwgbm90ZWJvb2tzIC0ga2VwdCBpbiB0aGVpciBvd24gc3ViZGlyZWN0b3J5IHdpdGhpbiB0aGUgcHJvamVjdCBkaXJlY3RvcnkpLgpvcHRzX2tuaXQkc2V0KHJvb3QuZGlyID0gcnByb2pyb290OjpmaW5kX3JzdHVkaW9fcm9vdF9maWxlKCkpCgojIyBzZXQga25pdHIgb3B0aW9ucyBmb3Iga25pdHRpbmcgY29kZSBpbnRvIHRoZSByZXBvcnQuCm9wdHNfY2h1bmskc2V0KGNhY2hlID0gVFJVRSwgIyBzYXZlIHJlc3VsdHMgc28gdGhhdCBjb2RlIGJsb2NrcyBhcmVuJ3QgcmUtcnVuIHVubGVzcyBjb2RlIGNoYW5nZXMKICAgICAgICAgICAgICAgYXV0b2RlcCA9IFRSVUUsICMgLi5vciB1bmxlc3MgYSByZWxldmFudCBlYXJsaWVyIGNvZGUgYmxvY2sgY2hhbmdlZAogICAgICAgICAgICAgICBjYWNoZS5jb21tZW50cyA9IEZBTFNFLCAjIGRvbid0IHJlLXJ1biBpZiB0aGUgb25seSB0aGluZyB0aGF0IGNoYW5nZWQgd2FzIHRoZSBjb21tZW50cwogICAgICAgICAgICAgICBoaWdobGlnaHQgPSBUUlVFLCAKICAgICAgICAgICAgICAgc21hbGwubWFyID0gVFJVRSkKYGBgCgpEZWZpbmUgdGhlIHdvcmtpbmcgc3ViZGlyZWN0b3JpZXMuICAKYGBge3Igd29ya3NwYWNlX3NldHVwfQojIyBwcmludCB0aGUgd29ya2luZyBkaXJlY3RvcnksIGp1c3QgdG8gYmUgb24gdGhlIHNhZmUgc2lkZQpwYXN0ZSgiWW91IGFyZSBoZXJlOiAiLCBnZXR3ZCgpKQoKZGF0YS5kaXIgPC0gImRhdGEiICAgICMjIGlucHV0IGRhdGEgZmlsZXMKZnVuY3Rpb25zLmRpciA8LSAiUiIgICMjIGZ1bmN0aW9ucyAmIHNjcmlwdHMKc2F2ZS5kaXIgPC0gIm91dHB1dCIgICMjIGNsZWFuIGRhdGEsIG91dHB1dCBmcm9tIG1vZGVscyAmIG1vcmUgY29tcGxleCBjYWxjdWxhdGlvbnMKZmlndXJlcy5kaXIgPC0gImZpZ3MiICMjIHBsb3RzICYgZmlndXJlcyAKYGBgCgpJbXBvcnQgbGlicmFyaWVzLiAgCmBgYHtyIGltcG9ydF9wYWNrYWdlcywgcmVzdWx0cyA9IEZBTFNFfQpsaWJyYXJ5KGhlcmUpICMjIHBhaW5sZXNzIHJlbGF0aXZlIHBhdGhzIHRvIHN1YmR1cmVjdG9yaWVzLCBldGMuCmxpYnJhcnkodGlkeXZlcnNlKSAjIyBkYXRhIG1hbmlwdWxhdGlvbiwgY2xlYW5pbmcsIGFnZ3JlZ2F0aW9uCmxpYnJhcnkodmlyaWRpcykgIyMgc21hcnQgJiBwcmV0dHkgY29sb3VyIHNjaGVtZXMKbGlicmFyeShtdmFidW5kKSAjIyBtdWx0aXZhcmlhdGUgbW9kZWxpbmcgYW5hbHlzZXMgaW4gZWNvbG9neQpsaWJyYXJ5KGJvcmFsKSAjIyBtb3JlIG11bHRpdmFyaWF0ZSBtb2RlbGluZyBhbmFseXNlcyBpbiBlY29sb2d5CmBgYAoKT3JnYW5pemUgc29tZSBjb21tb25seS11c2VkIGdncGxvdDIgbW9kaWZpY2F0aW9ucyBpbnRvIGEgbW9yZSBjb252ZW5pZW50IChhbmQgbGVzcyByZXBldGl0aXZlKSBmb3JtYXQuIE9uZSBkYXksIEkgTVVTVCBmaWd1cmUgb3V0IHRoZSBwcm9wZXIgd2F5IHRvIHNldCB0aGUgdGhlbWUuLiAgICAKYGBge3IgY3VzdG9tX2dncGxvdF9zZXR0aW5nc19oZWxwZXJzfQojIyBnZ3Bsb3Qgc2V0dGluZ3MgJiB0aGluZ3MgdGhhdCBJIGtlZXAgcmV1c2luZwojIGdncGxvdF90aGVtZSA8LSBsaXN0KAojICAgdGhlbWVfYncoKSwKIyAgIHRoZW1lKGVsZW1lbnRfdGV4dChmYW1pbHkgPSAiVGltZXMiKSkKIyApCgojIyBhbHdheXMgdXNlIGJsYWNrLWFuZC13aGl0ZSB0aGVtZQp0aGVtZV9zZXQodGhlbWVfYncoKSkKCiMjIGhlbHBlciB0byBhZGp1c3QgZ2dwbG90IHRleHQgc2l6ZSAmIGF2b2lkIHJlcGV0aXRpb25zIAp0ZXh0X3NpemUgPC0gZnVuY3Rpb24odGV4dC54ID0gTlVMTCwKICAgICAgICAgICAgICAgICAgICAgIHRleHQueSA9IE5VTEwsCiAgICAgICAgICAgICAgICAgICAgICB0aXRsZS54ID0gTlVMTCwKICAgICAgICAgICAgICAgICAgICAgIHRpdGxlLnkgPSBOVUxMLAogICAgICAgICAgICAgICAgICAgICAgbGVnZW5kLnRleHQgPSBOVUxMLAogICAgICAgICAgICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gTlVMTCwgCiAgICAgICAgICAgICAgICAgICAgICBzdHJpcC54ID0gTlVMTCwgCiAgICAgICAgICAgICAgICAgICAgICBzdHJpcC55ID0gTlVMTCkgewogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSB0ZXh0LngpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSB0ZXh0LnkpLAogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gdGl0bGUueCksCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSB0aXRsZS55KSwKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gbGVnZW5kLnRleHQpLCAKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IGxlZ2VuZC50aXRsZSksIAogICAgICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gc3RyaXAueCksIAogICAgICAgIHN0cmlwLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gc3RyaXAueSkKICAgICAgICApCn0KCgojIyBsb2cgeS9taW4gKyAxIHRyYW5zZm9ybSAtIHVzZWZ1bCBmb3Igc3BlY2llcyBjb3VudHMvYmlvbWFzcyBkYXRhIHZpc3VhbGl6YXRpb24KbG9nX3lfbWluIDwtIGZ1bmN0aW9uKHkpIHsKICBsb2coeSAvIG1pbih5W3kgPiAwXSkgKyAxKQp9CgpgYGAKCioqKiAgCgojIyMjICoqU2FuZCBzdGF0aW9ucyAoQnVyZ2FzIEJheSwgMjAxMy0yMDE0KSoqICAKSW1wb3J0IHpvb2JlbnRoaWMgYWJ1bmRhbmNlIGRhdGEgKGNsZWFuZWQgYW5kIHByZXBhcmVkKS4gIApgYGB7ciBpbXBvcnRfem9vX2FibmRfc2FuZH0Kem9vLmFibmQuc2FuZCA8LSByZWFkX2NzdihoZXJlKHNhdmUuZGlyLCAiYWJuZF9zYW5kX29yaWdfY2xlYW4uY3N2IikpCgojIyBjb252ZXJ0IHN0YXRpb24gdG8gZmFjdG9yIChiZXR0ZXIgc2FmZSB0aGFuIHNvcnJ5IGxhdGVyLCB3aGVuIHRoZSBzdGF0aW9ucyBhcmUgbm90IHBsb3R0ZWQgaW4gdGhlIG9yZGVyIEkgd2FudCB0aGVtKQooem9vLmFibmQuc2FuZCA8LSB6b28uYWJuZC5zYW5kICU+JSAKICAgIG11dGF0ZShzdGF0aW9uID0gZmFjdG9yKHN0YXRpb24sIGxldmVscyA9IGMoIktyYWltb3JpZSIsICJDaHVrYWx5YSIsICJBa2luIiwgIlNvem9wb2wiLCAiQWdhbGluYSIsICJQYXJhc2tldmEiKSkpCikKYGBgCgpSZW1vdmUgdGhlIGFsbC0wIHNwZWNpZXMgKD0gbm90IHByZXNlbnQgaW4gdGhlIGN1cnJlbnQgZGF0YXNldCkuICAKTWF5YmUgYWxzbyByZW1vdmUgdGhlIHNpbmdsZXRvbnMgKHNwZWNpZXMgYXBwZWFyaW5nIG9ubHkgb25jZSBpbiB0aGUgd2hvbGUgZGF0YXNldCBhbmQgcmVwcmVzZW50ZWQgYnkgYSBzaW5nbGUgaW5kaXZpZHVhbCA9IHNvIHJhcmUgdGhhdCBpdCdzIHVubGlrZWx5IHRoZXkgY2FycnkgaW1wb3J0YW50IGluZm9ybWF0aW9uLCBidXQgaXQgd291bGQgcHJvYmFibHkgaW1wcm92ZSB0aGUgcnVuIHRpbWVzKS4gIApgYGB7ciBmaWx0ZXJfem9vX2RhdGFfc2FuZH0KKHpvby5hYm5kLmZsdC5zYW5kIDwtIHpvby5hYm5kLnNhbmQgJT4lCiAgIHNlbGVjdCgtYyhzdGF0aW9uOnJlcGxpY2F0ZSkpICU+JQogICBzZWxlY3Qod2hpY2goY29sU3VtcyguKSA+IDApKQopCmBgYAoKCiMjIyMjICoqTFZNIC0gbW9kZWwtYmFzZWQgb3JkaW5hdGlvbioqClBlcmZvcm0gYSBtb2RlbC1iYXNlZCB1bmNvbnN0cmFpbmVkIG9yZGluYXRpb24gYnkgZml0aW5nIGEgcHVyZSBsYXRlbnQgdmFyaWFibGUgbW9kZWwgKHBhY2thZ2UgYm9yYWwgLSBIdWkgZXQgYWwuLCAyMDE0KS4gVGhpcyB3aWxsIGFsbG93IHRvIHZpc3VhbGl6ZSB0aGUgbXVsdGl2YXJpYXRlIHN0YXRpb25zIHggc3BlY2llcyBkYXRhIC0gc2ltaWxhciB0byBuTURTLCBjYW4gYmUgaW50ZXJwcmV0ZWQgaW4gdGhlIHNhbWUgd2F5LiAgIApJJ20gaW5jbHVkaW5nIGEgKGZpeGVkKSByb3cgZWZmZWN0IHRvIGFjY291bnQgZm9yIGRpZmZlcmVuY2VzIGluIHNpdGUgdG90YWwgYWJ1bmRhbmNlIC0gdGhpcyB3YXksIHRoZSBvcmRpbmF0aW9uIGlzIGluIHRlcm1zIG9mICoqc3BlY2llcyBjb21wb3NpdGlvbioqLiAgIApOQiB0aGlzIHRha2VzIGFib3V0IGEgbWlsbGlvbiB5ZWFycyB0byBydW4hIApgYGB7ciBsdm1fc2FuZH0KbHZtLnNhbmQgPC0gYm9yYWwoeSA9IHpvby5hYm5kLmZsdC5zYW5kLCAKICAgICAgICAgICAgICAgICAgZmFtaWx5ID0gIm5lZ2F0aXZlLmJpbm9taWFsIiwKICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICMjIHdlIHdhbnQgdG8gY29udHJvbCBmb3Igc2l0ZSBlZmZlY3RzIC0gdGhlcmUgYXJlIDYgc2l0ZXMgd2l0aCA5IHJlcGxpY2F0ZXMgZWFjaAogICAgICAgICAgICAgICAgICByb3cuZWZmID0gImZpeGVkIiwgcm93LmlkcyA9IG1hdHJpeChyZXAoMTo2LCBlYWNoID0gOSksIG5jb2wgPSAxKSwgIAogICAgICAgICAgICAgICAgICAjIyAyIGxhdGVudCB2YXJpYWJsZXMgPSAyIGF4ZXMgb24gd2hpY2ggdG8gcmVwcmVzZW50IHRoZSB6b29iZW50aGljIGRhdGEKICAgICAgICAgICAgICAgICAgbHYuY29udHJvbCA9IGxpc3QobnVtLmx2ID0gMikgCiAgICAgICAgICAgICAgICAgIAogICAgICMgICAgICAgICAgICAgICMjIGV4YW1wbGUgY29udHJvbCBzdHJ1Y3R1cmUsIHRvIGNoZWNrIGlmIGZ1bmN0aW9uIGRvZXMgd2hhdCBJIHdhbnQsIGJlY2F1c2Ugb3RoZXJ3aXNlIGl0IHRha2VzIGFuIGludG9sZXJhYmx5IGxvbmcgdGltZSwgYW5kIEknbGwgc2hvb3QgbXlzZWxmIGlmIEkgaGF2ZSB0byB3YWl0IGZvciBpdCBhZ2FpbgogICAgICMgICAgICAgICAgICAgIG1jbWMuY29udHJvbCA9IGxpc3Qobi5idXJuaW4gPSAxMCwgbi5pdGVyYXRpb24gPSAxMDAsCiAgICAgIyBuLnRoaW4gPSAxKQogICAgICMgICAgICAgICAgICAgIAogICAgIAogICAgICAgICAgICAgICAgICApCgpgYGAKCkNoZWNrIHRoZSBzdW1tYXJ5IGFuZCBkaWFnbm9zdGljIHBsb3RzIGZvciB0aGUgTFZNLiAgCmBgYHtyIHN1bW1hcnlfbHZtX3NhbmR9CnN1bW1hcnkobHZtLnNhbmQpCgojIyBtb2RlbCBmaXQgZGlhZ25vc3RpYyBwbG90cwpwbG90KGx2bS5zYW5kKQpgYGAKVGhlIHJlc2lkdWFscyBwbG90cyBsb29rIGZpbmUgKG5vIHBhdHRlcm5zIGluIHRoZSByZXNpZHVhbHMgdnMgZml0dGVkLCBzbyB2YXJpYW5jZSBpcyBob21vZ2VuZW91cywgdGhlIHF1YW50aWxlIHBsb3Qgc2hvd3MgYSBub3JtYWwgZGlzdHJpYnV0aW9uIG9mIHRoZSByZXNpZHVhbHMpIC0gdGhlIG1vZGVsIGZpdHMgdGhlIGRhdGEgcHJldHR5IHdlbGwuICAKClNhdmUgdGhlIHNhbmQgTFZNLiAgCmBgYHtyIHNhdmVfbHZtX3NhbmR9CndyaXRlX3Jkcyhsdm0uc2FuZCwgCiAgICAgICAgICBoZXJlKHNhdmUuZGlyLCAibHZtX3NhbmQuUkRTIikpCmBgYAoKRXhhbWluZSB0aGUgYmlwbG90IG9idGFpbmVkIGJ5IGZpdHRpbmcgdGhlIExWTSwgYXMgd2VsbCBhcyB0aGUgMjAgbW9zdCAiaW1wb3J0YW50IiBzcGVjaWVzLiAgIApgYGB7ciBjaGVja19iaXBsb3RfbHZtX3NhbmR9Cmx2c3Bsb3QobHZtLnNhbmQsIGppdHRlciA9IFQsIGJpcGxvdCA9IFRSVUUsIGluZC5zcHAgPSAyMCkKYGBgCgpBbGwgaW4gYWxsLCB0aGUgZmluYWwgcmVzdWx0IHJlc2VtYmxlcyB0aGUgbk1EUyBvcmRpbmF0aW9uIHZlcnkgbXVjaCAtIHNhbWUgNCBjbHVzdGVycyAoS3JhaW1vcmllICsgQ2h1a2FseWEsIEFLaW4sIEFnYWxpbmEsIFNvem9wb2wgKyBQYXJhc2tldmEpLiBLcmFpbW9yaWUgYW5kIENodWthbHlhIGFyZSBiZXR0ZXIgZGlzdGluZ3Vpc2hlZCBvbiB0aGUgTFZNIHBsb3QgdGhhbiBvbiB0aGUgTURTLCBidXQgc3RpbGwuICAKVGhlIHJ1biB0aW1lIGlzIGV4dHJlbWVseSwgZXh0cmVtZWx5IGxvbmcgKH4xaCksIGJ1dCB0aGUgZGF0YSBkb24ndCBuZWVkIHRvIGJlIHRyYW5zZm9ybWVkLCBhbmQgdGhlIG1vZGVsIGZpdCBjYW4gYmUgZXhhbWluZWQgYW5kIGFkanVzdGVkIGlmIG5lY2Vzc2FyeS4gICAgClRoZSBzcGVjaWVzIHNpbmdsZWQgb3V0IGFzIHNpZ25pZmljYW50IGFyZSBwcm9iYWJseSBzb21ld2hhdCBkaWZmZXJlbnQgLSBoYXZlIHRvIGNoZWNrISAgIAoKUmVkbyB0aGUgYmlwbG90LCBiZWNhdXNlIHRoaXMgb25lIGlzIG5vdCB2ZXJ5IHByZXR0eS4gSSdtIG5vdCBhZGRpbmcgdGhlIHNwZWNpZXMgb24gdG9wLCBmaXJzdCBiZWNhdXNlIEknbSB0b28gbGF6eSB0byBmaWd1cmUgb3V0IHRoZSBwcm9jZWR1cmUgZm9yIG9yZGVyaW5nIHRoZW0sIGFuZCBzZWNvbmQgYmVjYXVzZSB0aGUgcGxvdCBnZXRzIHRvbyBidXN5LiAgIApgYGB7ciBleHRyYWN0X2x2bV9jb29yZF9zYW5kfQojIyBleHRyYWN0IHRoZSBMViBjb29yZGluYXRlcyBvZiB0aGUgc3RhdGlvbnMgZnJvbSB0aGUgbW9kZWwsIHNvIHRoYXQgdGhlIHBsb3QgY2FuIGJlIHJlZG9uZSBpbiBnZ3Bsb3QgCmx2cy5jb29yZC5zYW5kIDwtIGFzX3RpYmJsZShsdm0uc2FuZCRsdi5tZWRpYW4pCgojIyBhZGQgdGhlIHN0YXRpb25zIGZyb20gdGhlIG9yaWdpbmFsIHpvb2JlbnRoaWMgdGFibGUgKG9yZGVyIHdhcyBub3QgbW9kaWZpZWQpCihsdnMuY29vcmQuc2FuZCA8LSBsdnMuY29vcmQuc2FuZCAlPiUgCiAgYmluZF9jb2xzKHpvby5hYm5kLnNhbmQgJT4lIHNlbGVjdChzdGF0aW9uKSkKKQoKYGBgCgpNYWtlIHRoZSBwbG90IGFuZCBzYXZlIGl0LiAgCmBgYHtyIHBsb3RfbHZtX3NhbmR9CihwbG90Lmx2bS5zYW5kIDwtIGdncGxvdChsdnMuY29vcmQuc2FuZCkgKyAKICAgIGdlb21fcG9pbnQoYWVzKHggPSBsdjEsIHkgPSBsdjIsIGNvbG91ciA9IHN0YXRpb24pKSArIAogICAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGUgPSAiU2V0MiIsIG5hbWUgPSAic3RhdGlvbiIsIAogICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IHBhc3RlMCgiUyIsIGFzLm51bWVyaWMoKHVuaXF1ZShsdnMuY29vcmQuc2FuZCAlPiUgcHVsbChzdGF0aW9uKSkpKSkpICsKICAgbGFicyh4ID0gIkxWMSIsIHkgPSAiTFYyIikKKQoKYGBgCgpgYGB7ciBzYXZlX2x2bV9wbG90X3NhbmR9CiMjIHNhdmUgdGhlIExWTSBwbG90IGZvciB0aGUgc2FuZCBzdGF0aW9ucwpnZ3NhdmUoZmlsZSA9IGhlcmUoZmlndXJlcy5kaXIsICJsdm1fc2FuZC5wbmciKSwgCiAgICAgICBwbG90Lmx2bS5zYW5kLCAKICAgICAgIHdpZHRoID0gMTUsIHVuaXRzID0gImNtIiwgZHBpID0gMzAwKQpgYGAKCgojIyMjIyAqKkdMTSBmaXR0aW5nIGZvciBhYnVuZGFuY2UgLSBlbnZpcm9ubWVudGFsIGRhdGEqKiAgCkxldCdzIGZpdCBHTE1zIHRvIHRoZSBzaXRlcyB4IHNwZWNpZXMgbWF0cml4IHRvIHRyeSBhbmQgZXhwbGFpbiB0aGUgb2JzZXJ2ZWQgZGlmZmVyZW5jZXMgaW4gY29tbXVuaXR5IHN0cnVjdHVyZSBieSB0aGUgdmFyaWF0aW9uIG9mIHRoZSBlbnZpcm9ubWVudGFsIHBhcmFtZXRlcnMuICAKVGhlc2UgZnVuY3Rpb25zIGFsbCBjb21lIGZyb20gcGFja2FnZSAqKm12YWJ1bmQqKi4gIApJbXBvcnQgdGhlIGVudmlyb25tZW50YWwgZGF0YSAtIHRoZSBvbmUgY2xlYW5lZCwgcHJlcGFyZWQgYW5kIHNhdmVkIGluIHRoZSBwcmV2aW91cyBub3RlYm9vayAoY2xhc3NpY2FsIG11bHRpdmFyaWF0ZSBtZXRob2RzKS4gSXQgY29udGFpbnMgbG9uZy10ZXJtIGF2ZXJhZ2VzIGZvciB0aGUgd2F0ZXIgY29sdW1uIGRhdGEgKDIwMDktMjAxMSArIDIwMTMtMjAxNCkgYXQgZWFjaCBzdGF0aW9uLCByZXBlYXRlZCBmb3IgZWFjaCByZXBsaWNhdGUsIGFuZCB0aGUgc2VkaW1lbnQgZGF0YSAoMjAxMy0yMDE0KSwgYWdhaW4gcmVwZWF0ZWQgdG8gdGhlIHNhbWUgbnVtYmVyIG9mIHJlcGxpY2F0ZXMuIE9ubHkgdGhlIHZhcmlhYmxlcyBkZXRlcm1pbmVkIHRvIGJlIHNpZ25pZmljYW50IGJ5IFBDQSBhcmUga2VwdC4gICAgICAgCmBgYHtyIGltcG9ydF9lbnZfZGF0YV9zYW5kfSAKZW52LnNhbmQgPC0gcmVhZF9jc3YoaGVyZShzYXZlLmRpciwgImVudl9kYXRhX29yZGluYXRpb25zX3NhbmQuY3N2IikpCgojIyBjb252ZXJ0IHN0YXRpb24gdG8gZmFjdG9yCihlbnYuc2FuZCA8LSBlbnYuc2FuZCAlPiUgCiAgICBtdXRhdGUoc3RhdGlvbiA9IGZhY3RvcihzdGF0aW9uLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiS3JhaW1vcmllIiwgIkNodWthbHlhIiwgIkFraW4iLCAiU296b3BvbCIsICJBZ2FsaW5hIiwgIlBhcmFza2V2YSIpKSkKKQpgYGAKU3RhdGlvbiBpcyBhIGZhY3RvciwgdGhlIHJlc3Qgb2YgdGhlIHZhcmlhYmxlcyBhcmUgbnVtZXJpYy4gIAoKVHVybiB0aGUgem9vYmVudGhpYyBkYXRhIChtaW51cyB0aGUgYWxsLTAgdGF4YSkgaW50byBhIG1hdHJpeCAtIGVhc2llciBmb3IgdGhlIG12YWJ1bmQgcGFja2FnZSBhbmQgbWV0aG9kcyB0byBkZWFsIHdpdGguICAKYGBge3IgbWF0cml4X2FibmRfc2FuZH0KIyMgdGhlcmUgaXMgYWxyZWFkeSBvbmUgc3Vic2V0IG9mIGZpbHRlcmVkIGNvdW50IGRhdGEgKDU0IHggMTQ3KSAtIHVzZSBpdCAKem9vLm12YWJuZC5zYW5kIDwtIG12YWJ1bmQoem9vLmFibmQuZmx0LnNhbmQpCmBgYAoKIyMjIyMjICoqbWFueUdMTSBieSBMVk0gY2x1c3RlcnMqKgpGaXJzdCwgbGV0J3Mgc2VlIGlmIHRoZSBncm91cHMgZnJvbSB0aGUgbGF0ZW50IHZhcmlhYmxlIG1vZGVsIChtb3JlIG9yIGxlc3MgZXF1YWwgdG8gdGhlIGNsdXN0ZXJzIGZyb20gdGhlIGNsYXNzaWNhbCBvcmRpbmF0aW9uKSBhcmUgdmFsaWQsIGFuZCB3aGljaCBzcGVjaWVzIGV4aGliaXQgYSByZXNwb25zZS4gIApgYGB7ciBjbHVzdGVyc19sdm1fc2FuZH0KIyMgY29uc3RydWN0IHRoZSB2ZWN0b3Igb2YgdGhlIGNsdXN0ZXJzIGJ5IGhhbmQsIGl0J3MgZWFzaWVyIHRoYXQgd2F5Li4gCmx2bS5jbHVzdGVycy5zYW5kIDwtIGMocmVwKDEsIHRpbWVzID0gMTgpLCByZXAoMjo0LCBlYWNoID0gOSksIHJlcCgzLCB0aW1lcyA9IDkpKQoKIyMgY29udmVydCB0byBmYWN0b3IKKGx2bS5jbHVzdGVycy5zYW5kIDwtIGZhY3Rvcihsdm0uY2x1c3RlcnMuc2FuZCkpCmBgYAoKQ2hlY2sgdGhlIG1vZGVsIGFzc3VtcHRpb25zLiAKMS4gTWVhbi12YXJpYW5jZSBhc3N1bXB0aW9uID0+IGRldGVybWluZXMgdGhlIGNob2ljZSBvZiBmYW1pbHkgcGFyYW1ldGVyLiBDYW4gYmUgY2hlY2tlZCBieSBwbG90dGluZyByZXNpZHVhbHMgdnMgZml0czogaWYgbGl0dGxlIHBhdHRlcm4gLSB0aGUgY2hvc2VuIG1lYW4tdmFyaWFuY2UgYXNzdW1wdGlvbiBpcyBwbGF1c2libGUuICAKQW5vdGhlciB3YXk6IGRpcmVjdCBwbG90dGluZyAodmFyaWFuY2UgfiBtZWFuKSwgZm9yIGVhY2ggc3BlY2llcyB3aXRoaW4gZWFjaCBmYWN0b3IKbGV2ZWwuICAKYGBge3IgY2hlY2tfbWVhbl92YXJpYW5jZV9sdm1fc2FuZH0KcGxvdChtYW55Z2xtKHpvby5tdmFibmQuc2FuZCB+IGx2bS5jbHVzdGVycy5zYW5kLCBmYW1pbHkgPSAibmVnYXRpdmUuYmlub21pYWwiKSkKCm1lYW52YXIucGxvdCh6b28ubXZhYm5kLnNhbmQgfiBsdm0uY2x1c3RlcnMuc2FuZCwgdGFibGUgPSBUUlVFKQpgYGAKCkl0J3Mgbm90IHBlcmZlY3QsIGJ1dCBpdCdzIG5vdCB0b28gdGVycmlibGUgZWl0aGVyLiAKCjIuIEFzc3VtZWQgcmVsYXRpb25zaGlwIGJldHdlZW4gbWVhbiBhYnVuZGFuY2UgYW5kIGVudmlyb25tZW50YWwgdmFyaWFibGVzIC0gbGluayBmdW5jdGlvbiBhbmQgZm9ybXVsYS4KV2hlbiBxdWFudGl0YXRpdmUgdmFyaWFibGVzIGFyZSBpbmNsdWRlZCBpbiB0aGUgbW9kZWwgKGZvciBub3csIG5vdCByZWxldmFudCAtIHdpbGwgYmUgaW4gdGhlIG5leHQgbW9kZWwpIC0+IGlmIHRoZXJlIGlzIGEgdHJlbmQgaW4gc2l6ZSBvZiByZXNpZHVhbHMgYXQgZGlmZmVyZW50IGZpdHRlZCB2YWx1ZXMgKGUuZy4gVS1zaGFwZSwuLikgPSB2aW9sYXRpb24gb2YgdGhlIGxvZy1saW5lYXJpdHkgYXNzdW1wdGlvbi4KICAKRXZlcnl0aGluZyBsb29rcyBtb3JlIG9yIGxlc3MgZmluZTsgZml0IHRoZSBtb2RlbC4gCmBgYHtyIGZpdF9nbG1zX2x2bV9zYW5kfQpnbG1zLmx2bS5zYW5kIDwtIG1hbnlnbG0oem9vLm12YWJuZC5zYW5kIH4gbHZtLmNsdXN0ZXJzLnNhbmQsIAogICAgICAgICAgICAgICAgICAgICAgICAgZmFtaWx5ID0gIm5lZ2F0aXZlLmJpbm9taWFsIikKCmBgYAoKRXhwbG9yZSB0aGUgZml0IChyZXNpZHVhbHMsIGRpYWdub3N0aWMgcGxvdHMsIGV0Yy4pLiAgCmBgYHtyIGV4cGxvcmVfZ2xtc19sdm1fc2FuZH0KIyMgcmVzaWR1YWxzIHZzIGZpdHRlZCB2YWx1ZXMKcGxvdChnbG1zLmx2bS5zYW5kKQoKIyMgYWxsIHRyYWRpdGlvbmFsIChnKWxtIGRpYWdub3N0aWMgcGxvdHMKcGxvdC5tYW55Z2xtKGdsbXMubHZtLnNhbmQsIHdoaWNoID0gMTozKQoKCiMgcG5nKGZpbGVuYW1lID0gaGVyZShmaWd1cmVzLmRpciwgImRpYWdfcGxfc2FuZDEucG5nIiksIHdpZHRoID0gMTYsIGhlaWdodCA9IDEwLCB1bml0cyA9ICJjbSIsIHJlcyA9IDMwMCkKIyBwbG90Lm1hbnlnbG0oZ2xtcy5sdm0uc2FuZCwgd2hpY2ggPSAyKQojIGRldi5vZmYoKQoKCiMjIyBzb3VyY2UgbXZhYnVuZCBHTE0gcGxvdHRpbmcgZnVuY3Rpb25zIG1vZGlmaWVkIHRvIHVzZSBhIGdyZXkgcGFsZXR0ZSAtIEkganVzdCBjYW4ndCByZWRvIHRoZXNlIHBsb3RzIG9uIG15IG93biwgdGhlIGZ1bmN0aW9uIGlzIGRvaW5nIHRvbyBjb21wbGljYXRlZCB0aGluZ3MgaW50ZXJuYWxseSB0byBzY2FsZSB0aGUgeCBhbmQgeSBheGVzCnNvdXJjZShoZXJlKGZ1bmN0aW9ucy5kaXIsICJkZWZhdWx0LnBsb3QubWFueWdsbV9ncmV5LlIiKSkKc291cmNlKGhlcmUoZnVuY3Rpb25zLmRpciwgInBsb3QubWFueWdsbV9ncmV5LlIiKSkKCnBhcihtZnJvdyA9IGMoMiwyKSkKbGFwcGx5KDE6MywgZnVuY3Rpb24oaSkgcGxvdC5tYW55Z2xtLmdyZXkoZ2xtcy5sdm0uc2FuZCwgd2hpY2ggPSBpLCBzdWIuY2FwdGlvbiA9ICIiKSkKcGFyKG1mcm93ID0gYygxLCAxKSkKCmBgYAoKSSByZWFsbHkgZG9uJ3QgbGlrZSB0aGUgcmFpbmJvdyBwYWxldHRlLCBidXQgSSB3b3VsZCBsaWtlIHRvIGluY2x1ZGUgdGhlc2UgcGxvdHMgaW4gbXkgdGhlc2lzIHJlc3VsdHMuLiBXaWxsIGhhdmUgdG8gZG8gc29tZXRoaW5nIGFib3V0IGl0LCBqdXN0IG5vdCByaWdodCBub3cuICAKU2F2ZSB0aGUgbW9kZWwhICAKYGBge3Igc2F2ZV9nbG1zX2x2bV9zYW5kfQp3cml0ZV9yZHMoZ2xtcy5sdm0uc2FuZCwgCiAgICAgICAgICBoZXJlKHNhdmUuZGlyLCAiZ2xtc19sdm1fc2FuZC5SRFMiKSkKYGBgCgpMZXQncyBzZWUgdGhlIG1vZGVsIHN1bW1hcnkgKE5CIHRha2VzIGEgTE9UIG9mIHRpbWUgaWYgdGhlcmUgYXJlIG1hbnkgcmVzYW1wbGluZ3MhKS4gIApgYGB7ciBzdW1tYXJ5X2dsbXNfbHZtX3NhbmR9CihnbG1zLmx2bS5zYW5kLnN1bW1hcnkgPC0gc3VtbWFyeShnbG1zLmx2bS5zYW5kLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRlc3QgPSAiTFIiLCBwLnVuaSA9ICJhZGp1c3RlZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuQm9vdCA9IDk5OSwgIyMgbGltaXQgdGhlIG51bWJlciBvZiBwZXJtdXRhdGlvbnMgaWYgeW91IGp1c3Qgd2FudCB0byBjaGVjayBpdCBvdXQKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNob3cudGltZSA9ICJhbGwiKQopCmBgYAoKVGhlIGZhY3RvciAoaGVyZSAtIGdyb3VwcyBvdXRsaW5lZCBieSB0aGUgTFZNKSBpcyBoaWdobHkgc2lnbmlmaWNhbnQgYWNjb3JkaW5nIHRvIHRoZSBtb2RlbHMuICAKVGhpcyBhbHNvIGFsbG93cyB1cyB0byBzZWUgd2hpY2ggc3BlY2llcyBleGhpYml0IGEgcmVzcG9uc2UgdG8gdGhlIGNob3NlbiBmYWN0b3IuIApUaGUgTFIgKGxpa2VsaWhvb2QgcmF0aW8pIHN0YXRpc3RpYyBpcyB1c2VkIGFzIGEgbWVhc3VyZSBvZiB0aGUgc3RyZW5ndGggb2YgaW5kaXZpZHVhbCB0YXhvbiBjb250cmlidXRpb25zIHRvIHRoZSBvYnNlcnZlZCBwYXR0ZXJucy4gCkknbGwgc2F2ZSB0aGUgc3VtbWFyeSBmb3Igc2FmZWtlZXBpbmcsIGJ1dCBJJ2xsIGFsc28gcnVuIGFuIGFub3ZhIC0gdG8gZ2V0IGFuIGFuYWx5c2lzIG9mIGRldmlhbmNlIHRhYmxlIG9uIHRoZSBtb2RlbCBmaXQgKGFsc28gYmV0dGVyIGZvciBleHRyYWN0aW5nIHRoZSBzcGVjaWVzIGNvbnRyaWJ1dGlvbnMsIG9yIGF0IGxlYXN0IEkga25vdyBob3cgdG8gZG8gaXQpLiAgCmBgYHtyIHNhdmVfc3VtbWFyeV9nbG1zX2x2bV9zYW5kfQp3cml0ZV9yZHMoZ2xtcy5sdm0uc2FuZC5zdW1tYXJ5LCAKICAgICAgICAgIGhlcmUoc2F2ZS5kaXIsICJnbG1zX2x2bV9zYW5kX3N1bW1hcnkuUkRTIikpCmBgYAoKUnVuIHRoZSBhbm92YSBvbiB0aGUgbW9kZWwuIApgYGB7ciBhbm92YV9nbG1zX2x2bV9zYW5kfQooZ2xtcy5sdm0uc2FuZC5hb3YgPC0gYW5vdmEubWFueWdsbShnbG1zLmx2bS5zYW5kLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVzdCA9ICJMUiIsIHAudW5pID0gImFkanVzdGVkIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5Cb290ID0gOTk5LCAjIyBsaW1pdCB0aGUgbnVtYmVyIG9mIHBlcm11dGF0aW9ucyBmb3IgYSBzaG9ydGVyIHJ1biB0aW1lICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNob3cudGltZSA9ICJhbGwiKSAKKQpgYGAKSSBwcm9iYWJseSBzaG91bGRuJ3QgaGF2ZSBwcmludGVkIGFsbCB0aGlzIG91dCwgYnV0IG9oIHdlbGwgd2hvIGNhcmVzLiAgCgpTYXZlIHRoZSBBTk9WQSwgdG9vLiAgCmBgYHtyIHNhdmVfYW5vdmFfZ2xtc19sdm1fc2FuZH0Kd3JpdGVfcmRzKGdsbXMubHZtLnNhbmQuYW92LCAKICAgICAgICAgIGhlcmUoc2F2ZS5kaXIsICJnbG1zX2x2bV9zYW5kX2Fub3ZhLlJEUyIpKQpgYGAKCk5PVyBsZXQncyBnZXQgdGhlIHRheGEgd2l0aCB0aGUgaGlnaGVzdCBjb250cmlidXRpb25zIHRvIHRoZSB0ZXN0ZWQgcGF0dGVybiAoaGVyZSAtIGNsdXN0ZXJzIGluIHRoZSBMVk0sIHdoaWNoIGFyZSByZWFsbHkgdGhlIGRpZmZlcmVudCBzb2Z0LWJvdHRvbSBoYWJpdGF0cykuICAKYGBge3IgcmVsYXRpdmVfdGF4b25fY29udHJpYl9nbG1zX2x2bV9zYW5kfQp0b3Bfbl9zcF9nbG0gPC0gZnVuY3Rpb24oZ2xtcy5hb3YsIHRvdC5kZXYuZXhwbCA9IDAuNzUpIHsKICAjIyBoZWxwZXIgcmV0cmlldmluZyB0aGUgdG9wIG4gc3BlY2llcyB3aXRoIHRoZSBoaWdoZXN0IGNvbnRyaWJ1dGlvbiB0byB0aGUgcGF0dGVybnMgdGVzdGVkIGJ5IHRoZSBHTE1zLCBpbiBkZWNyZWFzaW5nIG9yZGVyLgogICMjIEFyZ3VtZW50czogZ2xtcy5hb3YgLSByZXN1bHRzIGZyb20gYW4gQU5PVkEgb24gdGhlIGZpdHRlZCBHTE1zCiAgIyMgICAgICAgICAgICBkZXYuZXhwbGFpbmVkIC0gcHJvcG9ydGlvbiBvZiBleHBsYWluZWQgZGV2aWFuY2UgdG8gdXNlIGFzIGN1dG9mZgogIAogICMjIGdldCB0aGUgY2hhbmdlIGluIGRldmlhbmNlIGR1ZSB0byB0aGUgdGVzdGVkIHBhdHRlcm4gKD0gMm5kIHJvdyBmcm9tIHRhYmxlIG9mIHVuaXZhcmlhdGUgdGVzdCBzdGF0cyksIGFuZCBzb3J0IHRoZSBzcGVjaWVzIGluIG9yZGVyIG9mIGRlY3JlYXNpbmcgY29udHJpYnV0aW9uCiAgdW5pLnNvcnRlZCA8LSBzb3J0KGdsbXMuYW92JHVuaS50ZXN0WzIsIF0sIGRlY3JlYXNpbmcgPSBUUlVFLCBpbmRleC5yZXR1cm4gPSBGQUxTRSkKCiAgIyMgc3RhcnQgYXQgMTAgc3BlY2llcyBhbmQgY2hlY2sgaG93IG11Y2ggb2YgdGhlIGRldmlhbmNlIGlzIGV4cGxhaW5lZCBieSB0aGVpciBjb250cmlidXRpb25zLiBSZXBlYXQsIGluY3JlYXNpbmcgYnkgaW5jcmVtZW50cyBvZiAxMCB1bnRpbCB0aGUgZGVzaXJlZCBleHBsYWluZWQgZGV2aWFuY2UgKHNldCBhdCBmdW5jdGlvbiBjYWxsKSBpcyByZWFjaGVkLiAKICB0b3Aubi5zcCA8LSAxMAogIGRldi5leHBsIDwtIHN1bSh1bmkuc29ydGVkWzE6dG9wLm4uc3BdKS9zdW0odW5pLnNvcnRlZCkKICAKICB3aGlsZShkZXYuZXhwbCA8IHRvdC5kZXYuZXhwbCkgewogICAgdG9wLm4uc3AgPC0gdG9wLm4uc3AgKyAxMAogICAgZGV2LmV4cGwgPC0gc3VtKHVuaS5zb3J0ZWRbMTp0b3Aubi5zcF0pL3N1bSh1bmkuc29ydGVkKQogIH0KICAKICAjIyBwcmludCB0aGUgdG90YWwgZGV2aWFuY2UgZXhwbGFpbmVkIC0ganVzdCBmb3IgaW5mb3JtYXRpb24KICBwcmludChwYXN0ZSgiVG90YWwgZGV2aWFuY2UgZXhwbGFpbmVkOiIsIHJvdW5kKGRldi5leHBsLCAzKSkpCiAgCiAgIyMgcmV0dXJuIHRoZSBmaW5hbCB0b3Agc3BlY2llcyAoYW5kIHRoZWlyIHVuaXZhcmlhdGUgY29udHJpYnV0aW9ucywganVzdCBpbiBjYXNlKSAKICB0b3Auc3AgPC0gdW5pLnNvcnRlZFsxOnRvcC5uLnNwXQogIHJldHVybih0b3Auc3ApCn0KCiMjIGdldCB0aGUgdG9wIGNvbnRyaWJ1dGluZyBzcGVjaWVzIGZvciB0aGUgaW5pdGlhbCBzYW5kIEdMTXMgCih0b3Auc3AuZ2xtcy5sdm0uc2FuZCA8LSB0b3Bfbl9zcF9nbG0oZ2xtcy5sdm0uc2FuZC5hb3YsIHRvdC5kZXYuZXhwbCA9IDAuNzUpCikKCiMjIHVuZm9ydHVuYXRlbHksIG12YWJ1bmQgbGlrZXMgdG8gcmVuYW1lIG15IHNwZWNpZXMgd2hlbiBjb252ZXJ0aW5nIHRoZSBkYXRhIHRvIG1hdHJpeCAobm8gc3BhY2VzIGluIG5hbWVzKSwgYW5kIHNpbmNlIEknbSBnb2luZyB0byBsb29rIHRoZW0gdXAgaW4gbXkgaW5pdGlhbCB1bnRyYW5zZm9ybWVkIGNvdW50IGRhdGEsIEkgaGF2ZSB0byBjaGFuZ2UgdGhlbSBiYWNrLi4gICAKbmFtZXModG9wLnNwLmdsbXMubHZtLnNhbmQpIDwtIG5hbWVzKHRvcC5zcC5nbG1zLmx2bS5zYW5kKSAlPiUgCiAgc3RyX3JlcGxhY2UocGF0dGVybiA9ICJcXC4iLCByZXBsYWNlbWVudCA9ICIgIikKCnRvcC5zcC5nbG1zLmx2bS5zYW5kCmBgYAoKVHJ5IHRvIHBsb3QgdGhlc2UgdG9wIGNvbnRyaWJ1dGluZyBzcGVjaWVzIC0gZm9yIHdoYXRldmVyIHRoYXQncyB3b3J0aCwgYmVjYXVzZSA1MCBzcGVjaWVzIG9uIGEgcGxvdCBpcyBhIG1vbnN0cm9zaXR5LiAgCgpgYGB7ciBwbG90X3JlbGF0aXZlX3RheG9uX2NvbnRyaWJfZ2xtc19sdm1fc2FuZH0KIyMgZ2V0IHRoZSBzcGVjaWVzIGFuZCB0aGVpciBhYnVuZGFuY2VzIGZyb20gdGhlIG9yaWdpbmFsIGNvdW50IGRhdGEsIGFuZCB0cmFuc2Zvcm0gdGhlbSB0byBsb25nIGZvcm1hdAooYWJuZC50b3Auc3AuZ2xtcy5sdm0uc2FuZCA8LSB6b28uYWJuZC5zYW5kICU+JSAKICAgc2VsZWN0KHN0YXRpb24sIG5hbWVzKHRvcC5zcC5nbG1zLmx2bS5zYW5kKSkgJT4lIAogICBnYXRoZXIoa2V5ID0gInNwZWNpZXMiLCB2YWx1ZSA9ICJjb3VudCIsIC1zdGF0aW9uKSAlPiUgCiAgICMjIHR1cm4gc3BlY2llcyBpbnRvIGEgZmFjdG9yLCBvciB5b3UnbGwgYmUgdmVyeSB2ZXJ5IHNvcnJ5IGxhdGVyLCB3aGVuIHRoZXkncmUgb3V0IG9mIG9yZGVyIG9uIHRoZSBwbG90LiBOQiBuZWVkIHRvIGJlIGluIFJFVkVSU0Ugb3JkZXIsIGJlY2F1c2UgZ2dwbG90IHBsb3RzIGZyb20gYm90dG9tIHRvIHRvcCwgYW5kIEkgd2FudCB0aGUgdG9wLWNvbnRyaWJ1dGluZyBzcGVjaWVzIG9uIHRvcC4gCiAgIG11dGF0ZShzcGVjaWVzID0gZmFjdG9yKHNwZWNpZXMsIGxldmVscyA9IHJldihuYW1lcyh0b3Auc3AuZ2xtcy5sdm0uc2FuZCkpKSkKKQoKcGxvdF90b3BfbiA8LSBmdW5jdGlvbih0b3Aubi5zcC5kYXRhLCBtYXBwaW5nLCBsYWJzLmxlZ2VuZCwgbGFiLnksIHBhbGV0dGUpIHsKICAjIyBoZWxwZXIgZm9yIHBsb3R0aW5nIHRvcCBuIHNwZWNpZXMuIFdhcyBob3BpbmcgdG8gYXZvaWQgcmVwZWF0aW5nIGl0IGZyb20gd2F5IGJhY2sgd2hlbiwgYnV0IG5vIGRpY2UuIAogICMjIEFyZ3VtZW50czogdG9wLm4uc3AuZGF0YSAtIGRhdGEgZnJhbWUgKGxvbmcpIG9mIHRvcCBzcGVjaWVzJyBjb3VudHMvYmlvbWFzc2VzIGF0IHRoZSBkaWZmZXJlbnQgc3RhdGlvbnMKICAjIyAgICAgICAgICAgIG1hcHBpbmcgLSBtYXBwaW5ncyBvZiB0aGUgYWVzdGhldGljcwogICMjICAgICAgICAgICAgbGFicy5sZWdlbmQgLSBsYWJlbHMgdGhlIHVzZSBmb3IgdGhlIGxlZ2VuZCBlbnRyaWVzCiAgIyMgICAgICAgICAgICBsYWIueSAtIGN1c3RvbSBsYWJlbCBmb3IgeSBheGlzCiAgIyMgICAgICAgICAgICBwYWxldHRlIC0gY3VzdG9tIGNvbG91ciBwYWxldHRlIChmb3IgY29uc2lzdGVuY3kgd2l0aCBvdGhlciBwbG90cykKICAKICBnZ3Bsb3QodG9wLm4uc3AuZGF0YSwgbWFwcGluZykgKwogICAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNzUpICsgIyBtYWtlIHBvaW50cyBsYXJnZXIgJiBwYXJ0aWFsbHkgdHJhbnNwYXJlbnQKICAgIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gcGFsZXR0ZSwgIGxhYmVscyA9IGxhYnMubGVnZW5kKSArIAogICAgeWxhYihsYWIueSkgKyAKICAgIGNvb3JkX2ZsaXAoKSAKfQoKCihwbG90LnRvcC5zcC5nbG1zLmx2bS5zYW5kIDwtIHBsb3RfdG9wX24oYWJuZC50b3Auc3AuZ2xtcy5sdm0uc2FuZCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBzcGVjaWVzLCB5ID0gbG9nX3lfbWluKGNvdW50KSwgY29sb3VyID0gc3RhdGlvbiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFicy5sZWdlbmQgPSBwYXN0ZTAoIlMiLCBhcy5udW1lcmljKHVuaXF1ZShhYm5kLnRvcC5zcC5nbG1zLmx2bS5zYW5kJHN0YXRpb24pKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiLnkgPSAiQWJ1bmRhbmNlIChsb2coeS9taW4gKyAxKSkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhbGV0dGUgPSAiU2V0MiIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCgopCmBgYAoKV2VsbCB0aGlzIGlzIGEgbmlnaHRtYXJpc2ggcGxvdC4uIEknbGwgcHJvYmFibHkganVzdCBwdXQgdGhpcyBhd2Z1bG5lc3MgaW4gYSB0YWJsZSBhbmQgY2FsbCBpdCBhIGRheSwgb3IgcGxheSB3aXRoIGx2c3Bsb3QgYW5kIHRoZSBtb2RlbGVkIG9yZGluYXRpb24gcGxvdCwgaWYgYSBwbG90IGlzIHdoYXQncyBuZWVkZWQuICAKCkV4dHJhY3QgdGhlIHRvcC1jb250cmlidXRpbmcgc3BlY2llcyB0byBlYWNoIGNsdXN0ZXIgKHRoaXMgc2FtZSBuaWdodG1hcmUgYWJvdmUsIGJ1dCBhcyBhIHRhYmxlKS4gVGhpcyBjaHVuayBpcyBob3BlbGVzc2x5IHVnbHkgYW5kIGNsdW1zeSAoYW5kIEknbGwgaGF2ZSB0byByZXBlYXQgaXQgZm9yIHRoZSBzZWFncmFzcywgdG9vISksIGJ1dCBJJ20gdGlyZWQgb2YgYmVpbmcgc3R1Y2sgb24gdGhpcy4gSSBzdGlsbCBoYXZlIG1hbnksIE1BTlkgbW9yZSB0aGluZ3MgdG8gZG8sIGFuZCBtb3JlIHRpbWUtY29uc3VtaW5nIG9uZXMgdG9vLi4gIApgYGB7ciB0YWJsZV9yZWxhdGl2ZV90YXhvbl9jb250cmliX2dsbXNfbHZtX3NhbmR9CnRvcF9zcF9nbG1zX3RhYmxlIDwtIGZ1bmN0aW9uKG1hbnlnbG1zLm9iai5zbXJ5LCBncm91cCwgcCA9IDAuMDUpIHsKICAjIyMgZXh0cmFjdHMgdGhlIHRvcCBzcGVjaWVzIGluIGEgZ3JvdXAgZm9yIHdoaWNoIHRoZXJlIGlzIGFuIG9ic2VydmVkIGVmZmVjdCBpbiBhIG1hbnlnbG0gdGVzdCwgYXQgdGhlIHNwZWNpZmllZCBwcm9iYWJpbGl0eSBsZXZlbC4KICAjIyMgUmV0dXJuczogdGliYmxlIHdpdGggdGhlIHRvcCBzcGVjaWVzIGZvciB0aGUgc3BlY2lmaWVkIGdyb3VwL2NsdXN0ZXIsIHNvcnRlZCAoZGVzY2VuZGluZykgYnkgdW5pdmFyaWF0ZSBMUiB2YWx1ZSBvZiB0aGUgc3BlY2llcywgc2lnbmlmaWNhbnQgYXQgdGhlIGdpdmVuIHAgbGV2ZWwuIAogIAogICMjIGV4dHJhY3QgdGhlIHVuaXZhcmlhdGUgTFIgY29lZmZpY2llbnRzIG9mIHRoZSBzcGVjaWVzIGFuZCB0aGVpciBwLXZhbHVlcyAKICBzcF91bml2YXIgPC0gYXNfdGliYmxlKG1hbnlnbG1zLm9iai5zbXJ5JHVuaS50ZXN0LCByb3duYW1lcyA9ICJzcGVjaWVzIikKICBzcF9wIDwtIGFzX3RpYmJsZShtYW55Z2xtcy5vYmouc21yeSR1bmkucCwgcm93bmFtZXMgPSAic3BlY2llcyIpCgogICMjIGNvbWJpbmUgaW4gdGhlIHNhbWUgdGliYmxlCiAgc3BfYWxsIDwtIGxlZnRfam9pbihzcF91bml2YXIsIHNwX3AsIGJ5ID0gInNwZWNpZXMiKSAgCiAgCiAgIyMgcmVuYW1lIHRoZSBjb2x1bW5zCiAgc3BfYWxsIDwtIHNwX2FsbCAlPiUgCiAgICByZW5hbWVfYXQodmFycyhjb250YWlucygiLngiKSksIGxpc3QofnN0cl9yZXBsYWNlX2FsbCguLCBwYXR0ZXJuID0gIi54IiwgIi5MUiIpKSkgJT4lIAogICAgcmVuYW1lX2F0KHZhcnMoY29udGFpbnMoIi55IikpLCBsaXN0KH5zdHJfcmVwbGFjZV9hbGwoLiwgcGF0dGVybiA9ICIueSIsICIucCIpKSkKICAKICAjIyBmaWx0ZXIgb25seSB0aGUgZ3JvdXAvY2x1c3RlciB3ZSB3YW50LCBhdCB0aGUgcC1sZXZlbCB3ZSB3YW50CiAgc3BfYWxsX2ZsdCA8LSBzcF9hbGwgJT4lIAogICAgc2VsZWN0KHNwZWNpZXMsIGNvbnRhaW5zKGdyb3VwKSkgJT4lIAogICAgZmlsdGVyX2F0KHZhcnMoY29udGFpbnMoIi5wIikpLCBhbGxfdmFycyguIDwgcCkpICU+JQogICAgYXJyYW5nZV9hdCh2YXJzKGNvbnRhaW5zKCIuTFIiKSksIGxpc3QofmRlc2MoLikpKQoKfQoKdG9wLnNwLmFibmQuZ2xtcy5sdm0uc2FuZCA8LSBsYXBwbHkobmFtZXMoZ2xtcy5sdm0uc2FuZC5zdW1tYXJ5JGFsaWFzZWQpLCBmdW5jdGlvbih4KSB0b3Bfc3BfZ2xtc190YWJsZShnbG1zLmx2bS5zYW5kLnN1bW1hcnksIHgsIHAgPSAwLjA1KSkgCgojIyBmaXggc3BlY2llcyBuYW1lcyAocmVtb3ZlIGRvdCkgCnRvcC5zcC5hYm5kLmdsbXMubHZtLnNhbmQgPC0gbGFwcGx5KHRvcC5zcC5hYm5kLmdsbXMubHZtLnNhbmQsIGZ1bmN0aW9uKHgpIHggJT4lIG11dGF0ZShzcGVjaWVzID0gc3RyX3JlcGxhY2Uoc3BlY2llcywgcGF0dGVybiA9ICJcXC4iLCByZXBsYWNlbWVudCA9ICIgIikpKQoKIyMgcmVuYW1lIGNvbHVtbnMgKD0gZ3JvdXAgbmFtZXMpIC0gcmlnaHQgbm93IHRoZXkgYXJlIHNvbWV0aGluZyBsaWtlICJsdm0uY2x1c3RlcnMuc2FuZDIiIGV0Yy4KdG9wLnNwLmFibmQuZ2xtcy5sdm0uc2FuZCA8LSBsYXBwbHkodG9wLnNwLmFibmQuZ2xtcy5sdm0uc2FuZCwgZnVuY3Rpb24oeCkgeCAlPiUgcmVuYW1lX2F0KHZhcnMoY29udGFpbnMoImx2bS5jbHVzdGVycy5zYW5kIikpLCBsaXN0KH5zdHJfcmVwbGFjZV9hbGwoLiwgcGF0dGVybiA9ICJsdm0uY2x1c3RlcnMuc2FuZCIsICJncm91cF8iKSkpKQoKdG9wLnNwLmFibmQuZ2xtcy5sdm0uc2FuZCA8LSBsYXBwbHkodG9wLnNwLmFibmQuZ2xtcy5sdm0uc2FuZCwgZnVuY3Rpb24oeCkgeCAlPiUgcmVuYW1lX2F0KHZhcnMoY29udGFpbnMoIkludGVyY2VwdCIpKSwgbGlzdCh+c3RyX3JlcGxhY2VfYWxsKC4sIHBhdHRlcm4gPSAiXFwoSW50ZXJjZXB0XFwpIiwgImdyb3VwXzEiKSkpKQoKCiMjIHB1bGwgdGhlIGFidW5kYW5jZXMgZnJvbSB0aGUgb3JpZ2luYWwgY291bnQgZGYgYW5kIGFkZCB0byB0aGUgc3VtbWFyeSBnbG0gdGFibGVzIAojIyBtYWtlIGEgbG9uZyBkZiBvZiBhYnVuZGFuY2VzICYgYWRkIGNsdXN0ZXJzICAKem9vLmFibmQuc2FuZC5sb25nIDwtIHpvby5hYm5kLnNhbmQgJT4lCiAgc2VsZWN0KC1jKG1vbnRoOnJlcGxpY2F0ZSkpICU+JQogIGdhdGhlcihrZXkgPSAic3BlY2llcyIsIHZhbHVlID0gImNvdW50IiwgLXN0YXRpb24pICU+JSAKICBtdXRhdGUoZ3JvdXAgPSBjYXNlX3doZW4oc3RhdGlvbiAlaW4lIGMoIktyYWltb3JpZSIsICJDaHVrYWx5YSIpIH4gMSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXRpb24gPT0gIkFraW4iIH4gMiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXRpb24gJWluJSBjKCJTb3pvcG9sIiwgIlBhcmFza2V2YSIpIH4gMywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXRpb24gPT0gIkFnYWxpbmEiIH4gNCkpCgojIyBzdW0gc3AgYWJ1bmRhbmNlcyBieSBncm91cDsgbmVzdCBieSBncm91cAp6b28uYWJuZC5zYW5kLmxvbmcuc21yeSA8LSB6b28uYWJuZC5zYW5kLmxvbmcgJT4lIAogIGdyb3VwX2J5KHNwZWNpZXMsIGdyb3VwKSAlPiUgCiAgc3VtbWFyaXNlKHRvdGFsX2NvdW50ID0gc3VtKGNvdW50KSkgJT4lIAogIGdyb3VwX2J5KGdyb3VwKSAlPiUKICBuZXN0KCkKCiMjIGFkZCB0aGUgY291bnRzIHRvIHRoZSBncm91cCBkZnMgLSB3b3cgdGhhdCdzIGFuIHVnbHksIHVnbHkgaGFjay4gV2lzaCBJIGhhZCBtb3JlIHRpbWUgdG8gd3JpdGUgdGhpcyB1cCBwcm9wZXJseS4uIAp0b3Auc3AuYWJuZC5nbG1zLmx2bS5zYW5kIDwtIG1hcDIodG9wLnNwLmFibmQuZ2xtcy5sdm0uc2FuZCwgem9vLmFibmQuc2FuZC5sb25nLnNtcnkgJT4lIHB1bGwoZ3JvdXApLCB+bGVmdF9qb2luKC54LCB6b28uYWJuZC5zYW5kLmxvbmcuc21yeSAlPiUgZmlsdGVyKGdyb3VwID09IC55KSAlPiUgdW5uZXN0KCksIGJ5ID0gInNwZWNpZXMiKSkKCiMjIHNpbmNlIHRoZXNlIGFyZSBzdW0gY291bnRzIG92ZXIgYWxsIHRoZSByZXBsaWNhdGVzICh0aGF0J3Mgd2h5IHRoZSBtb25zdHJvdXMgbnVtYmVycyksIGF2ZXJhZ2UgdGhlbSB0byBiZSBtZWFuIGNvdW50cyBwZXIgZ3JvdXAuIE5CIGRpZmZlcmVudCBncm91cHMgY29uc2lzdCBvZiBkaWZmZXJlbnQgbnVtYmVycyBvZiByZXBsaWNhdGVzLCBiLmMuIHNvbWUgZ3JvdXBzIGNvbnNpc3Qgb2YgbW9yZSB0aGFuIG9uZSBzdGF0aW9uCih0b3Auc3AuYWJuZC5nbG1zLmx2bS5zYW5kIDwtIG1hcDIodG9wLnNwLmFibmQuZ2xtcy5sdm0uc2FuZCwgYygxOCwgOSwgMTgsIDkpLCBmdW5jdGlvbih4LCB5KSB4ICU+JSBtdXRhdGUobWVhbl9jb3VudCA9IHRvdGFsX2NvdW50L3kpKQopCmBgYAoKVG8gZGV0ZXJtaW5lIHRoZSByZWxhdGl2ZSB0YXhvbiBjb250cmlidXRpb24gdG8gcGF0dGVybnM6IExSIHN0YXRpc3RpYyAtIGEgbWVhc3VyZSBvZiBzdHJlbmd0aCBvZiBpbmRpdmlkdWFsIHRheG9uIGNvbnRyaWJ1dGlvbnMuIExSIGV4cHJlc3NlcyBob3cgbWFueSB0aW1lcyBtb3JlIGxpa2VseSB0aGUgZGF0YSBhcmUgdW5kZXIgb25lIG1vZGVsIHRoYW4gdGhlIG90aGVyLiBUaGlzIGxpa2VsaWhvb2QgcmF0aW8sIG9yIGVxdWl2YWxlbnRseSBpdHMgbG9nYXJpdGhtLCBjYW4gdGhlbiBiZSB1c2VkIHRvIGNvbXB1dGUgYSBwLXZhbHVlLCBvciwgY29tcGFyZWQgdG8gYSBjcml0aWNhbCB2YWx1ZSwgdG8gZGVjaWRlIHdoZXRoZXIgdG8gcmVqZWN0IHRoZSBudWxsIG1vZGVsIGluIGZhdm91ciBvZiB0aGUgYWx0ZXJuYXRpdmUgbW9kZWwuICAKCkluIHRoaXMgY2FzZSwgdGhlIG1vZGVsIHNob3dzIHdoaWNoIHNwZWNpZXMgZXhoaWJpdCBhIHJlYWN0aW9uIGJhc2VkIG9uIHRoZSBjaG9zZW4gZ3JvdXBzIC0gaW4gb3RoZXIgd29yZHMsIHdoaWNoIHNwZWNpZXMgYXJlIG1vcmUgbGlrZWx5IHRvIGJlIG1vcmUvbGVzcyBhYnVuZGFudCBpbiBlYWNoIGdyb3VwLiAgCkZvciAqKmdyb3VwIDEqKiAoPSBTMS1TMiksIHRoZSBzcGVjaWVzL3RheGEgd2l0aCBzaWduaWZpY2FudGx5ICoqaGlnaGVyIGFidW5kYW5jZSoqIGFyZTogT2xpZ29jaGFldGEsIEguIGZpbGlmb3JtaXMsIFAuIGtlZmVyc3RlaW5pLCBNLiBwYWxtYXRhLCBQLiBjaXJyaWZlcmEsIEEuIGRpYWRlbWEgKGFtb25nIG90aGVycyk7IGFuZCB0aGUgb25lcyB3aXRoIHNpZ25pZmljYW50bHkgKipsb3dlciBhYnVuZGFuY2UqKiAtIGV2ZW4gMCwgaW4gc29tZSBjYXNlcyAtIFMuIGJpZGVudGF0YSwgQi5sYW5jZW9sYXR1bSwgTS4gcGFwaWxsaWNvcm5pcywgTWVsaXRhIHBhbG1hdGEsIFAuIGp1YmF0dXMsIGFuZCBzbyBvbi4gIApGb3IgKipncm91cCAyKiogKD0gUzMpLCB0aGUgc3BlY2llcyB3aXRoICoqaGlnaGVyIGFidW5kYW5jZSoqIGFyZTogQi4gbGFuY2VvbGF0dW0sIE8uIGxpbWFjaW5hLCBPbGlnb2NoYWV0YSAodGhpcyBpcyB0aGlzIHN0cmFuZ2UgYXJ0aWZhY3Qgb2YgMjAxMyksIFAuIGtlZmVyc3RlaW5pLCBMLiBmbGF2b2NhcGl0YXR1cy4gVGhlIHNwZWNpZXMgd2l0aCAqKmxvd2VyIGFidW5kYW5jZSoqIGFyZTogSC4gZmlsaWZvcm1pcywgQS4ga2Fnb3NoaW1lbnNpcywgTS4gc3RhbW1lcmksIE1lbGlubmEgcGFsbWF0YSwgZXRjLgpGb3IgKipncm91cCAzKiogKD0gUzQtUzYpLCB0aGUgc3BlY2llcyB3aXRoICoqaGlnaGVyIGFidW5kYW5jZSoqIGFyZTogQy4gZ2FsbGluYSwgTC4gbWVkaXRlcnJhbmV1bSAtIHdpdGggdmVyeSBoaWdoIGRvbWluYW5jZSBvdmVyIHByYWN0aWNhbGx5IGFsbCBvdGhlcnM7IGFsc28gUHNldWRvY3VtYSBsb25naWNvcm5lLCBTcGlvIGZpbGljb3JuaXMuIFRoZSBzcGVjaWVzIHdpdGggKipsb3dlciBhYnVuZGFuY2UqKiBhcmU6IEguIGZpbGlmb3JtaXMsIE9saWdvY2hhZXRlcyAodG8gYSBjZXJ0YWluIGV4dGVudCAtIHRoZXkgYXJlIHN0aWxsIHByZXNlbnQsIHRob3VnaCksIEEuIGthZ29zaGltZW5zaXMsIEwuIGtvcmVuaSwgSGFybW90aG9lIHJldGljdWxhdGEsIElwaGlub2UgdGVuZWxsYSwgTGVpb2Nob25lIGxlaW9weWdvcy4gIApGb3IgKipncm91cCA0KiogKD0gUzUpLCB0aGUgc3BlY2llcyB3aXRoICoqaGlnaGVyIGFidW5kYW5jZSoqIGFyZTogTWljcm9kZXV0b3B1cyB2ZXJzaWN1bGF0dXMsIEV1cnlkaWNlIGRvbGxmdXNpLCBNZWxpdGEgcGFsbWF0YSwgUG9seWdvcmRpdXMgbmVhcG9saXRhbnVzLCBQb2x5Y2lycnVzIGNhbGllbmRydW0sIFBvbHljaXJydXMganViYXR1cywgU3RyZXB0b3N5bGxpcyBiaWRlbnRhdGEuIFRoZSBzcGVjaWVzIHdpdGggKipsb3dlciBhYnVuZGFuY2UqKiBhcmU6IEEuIGthZ29zaGltZW5zaXMsIE1lbGlubmEgcGFsbWF0YSwgUC4gY2lycmlmZXJhLCBQLiBjaWxpYXRhLCBBLiBhbGJhLCBJLiB0ZW5lbGxhLiAgIApJIGxvdmUgaG93IHRoZSBzcGVjaWVzIHdpdGggdGhlIGhpZ2hlc3QgdmFyaWFuY2VzIChlLmcuIEMuIGdhbGxpbmEsIHRoZSBtb3N0IGNvbnNwaWN1b3VzIGV4YW1wbGUpIGFyZSBjb25zaXN0ZW50bHkgcHVzaGVkIGJhY2sgLSBoYXZlIGxvd2VyIExSIHNjb3Jlcy4gVGhpcyBpcyB2ZXJ5IGdvb2QgLSBDLiBnYWxsaW5hIGluIHBhcnRpY3VsYXIgaXMgZG9taW5hbnQgaW4gZ3JvdXAgMywgYnV0IGlzIHByZXNlbnQgYWxzbyBpbiBhbGwgb3RoZXIgZ3JvdXBzIC0gaXRzIHN1YnN0cmF0ZS9kZXB0aCBwcmVmZXJlbmNlcyBhcmUgdmVyeSB3aWRlLCBzbyB0aGlzIGlzIG5vdCB1bmNvbW1vbi4gSXQncyBub3QgYXV0b21hdGljYWxseSBwdXNoZWQgdG8gdGhlIHRvcCBvZiB0aGUgbGlzdCwgYnV0IGl0cyByZWFjdGlvbiBpcyBkZXRlY3RlZCBieSB0aGUgbWFueUdMTSB0ZXN0LiBOZWF0ISAKQ29udHJhc3QgdG8gdGhlIFNJTVBFUiByZXN1bHRzLCB3aGVyZSB0aGUgc3BlY2llcyB3aXRoIHRoZSBoaWdoZXN0IHZhcmlhbmNlIGFyZSBjb25zaXN0ZW50bHkgYXQgdGhlIHRvcCAtIHRoZXkgY29udHJpYnV0ZSB0aGUgbW9zdCB0byB0aGUgc2ltaWxhcml0eSwgYXMgcGVyIHRoZSB0ZXN0IGRlZmluaXRpb24uICAKCkknbSBnb2luZyB0byBzYXZlIHRoZXNlIGFzIHNlcGFyYXRlIGZpbGVzIChtYW51YWxseSksIHRoZW4gZm9ybWF0IHRoZW0gYXMgdGFibGVzIC0gSSBrbm93IGl0J3MgYSBzaGFtZSwgYnV0IEknbSB0b28gZnJ1c3RyYXRlZCB0byBmaWd1cmUgb3V0IGhvdyB0byBkbyBpdCBwcm9ncmFtbWF0aWNhbGx5LiAgCkknbGwgYWxzbyBwdXQgdGhlbSBpbiBhIHdvcmQgdGFibGUgaW4gbXkgZmluYWwgdGV4dCwgYmVjYXVzZSBJIGRvbid0IHdhbnQgdG8gZGVhbCB3aXRoIGEgbWlsbGlvbiBzZXBhcmF0ZSBvbmVzIChlbWJlZGRlZCBleGNlbCB0YWJsZXMgZG9uJ3Qgc3BsaXQgb3ZlciBtdWx0aXBsZSBwYWdlcykuICAKCioqTkIgSW4gbXkgdGV4dCwgSSdtIHN3aXRjaGluZyB0aGUgbmFtZXMvcGxhY2VzIG9mIGdyb3VwIDMgYW5kIDQsIHRvIGJlIGNvbnNpc3RlbnQgd2l0aCB0aGUgU0lNUEVSIGdyb3VwcyAoSSdtIE5PVCBnb2luZyB0byByZXBlYXQgYWxsIHRoaXMganVzdCB0byBoYXZlIHRoZSBudW1iZXJzIG1hdGNoIHVwKS4gU28gdGhlIGZpbGUgbmFtZXMsIHRhYmxlIG5hbWVzLCBldGMuIHJlbWFpbiBhcyBhYm92ZS4gQnV0IGluIHRoZSB0ZXh0LCBJJ2xsIGhhdmUgdGhlIGZvbGxvd2luZzogZ3JvdXAgMSA9IFMxLVMyLCBncm91cCAyID0gUzMsIGdyb3VwIDMgPSBTNSwgZ3JvdXAgNCA9IFM0LVM2LiBSRU1FTUJFUiBUSElTIFNPIFRIRVJFIElTIE5PIENPTkZVU0lPTiEqKgoKCiMjIyMjIyAqKm1hbnlHTE0gYnkgZW52aXJvbm1lbnRhbCBwYXJhbWV0ZXJzKiogIApOb3csIGxldCdzIHRyeSB0byBzZWUgYSBkaWZmZXJlbnQgdGhpbmcgLSB3aGljaCBlbnZpcm9ubWVudGFsIHBhcmFtZXRlcnMgYmVzdCBkZXNjcmliZSB0aGUgc3BlY2llcyByZXNwb25zZS4gIApJJ20gZ29pbmcgdG8gdXNlIHRoZSBQQ0EtZmlsdGVyZWQgZW52aXJvbm1lbnRhbCBkYXRhIC0gaXQncyBzdGlsbCBnb2luZyB0byBiZSBhIHNsb2csIHdpdGggNyBwb3RlbnRpYWwgcHJlZGljdG9ycy4uICAKRmlyc3QsIGNvbnN0cnVjdCB0aGUgZm9ybXVsYSBmb3IgdGhlIG1vZGVsIC0gd2lsbCBkbyBpdCBzZXBhcmF0ZWx5IGluIGNhc2UgSSBuZWVkIHRvIHVwZGF0ZSBpdCBsYXRlciwgZXRjLiBUaGlzIGlzIHRoZSBmdWxsIGZvcm11bGEgd2l0aCBhbGwgZXhwbGFuYXRvcnkgdmFyaWFibGVzLiAgICAKYGBge3IgZm9ybXVsYV9lbnZfbWFueWdsbV9mdWxsX3NhbmR9Cihmb3JtdWxhLmVudi5nbG1zLnNhbmQgPC0gZm9ybXVsYShwYXN0ZSgiem9vLm12YWJuZC5zYW5kIH4iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3RlKGVudi5zYW5kICU+JSBzZWxlY3QoLXN0YXRpb24pICU+JSBuYW1lcygpLCBjb2xsYXBzZSA9ICIrIikpKQopCmBgYAoKRml0IHRoZSBHTE1zIHRvIHRoZSBzYW5kIGFidW5kYW5jZSBkYXRhLiAKYGBge3IgZml0X2dsbXNfZW52X2Z1bGxfc2FuZH0KZW52LmdsbXMuc2FuZCA8LSBtYW55Z2xtKGZvcm11bGEuZW52LmdsbXMuc2FuZCwKICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBlbnYuc2FuZCwKICAgICAgICAgICAgICAgICAgICAgICAgIGZhbWlseSA9ICJuZWdhdGl2ZS5iaW5vbWlhbCIpCgpgYGAKCkV4cGxvcmUgdGhlIGZpdCAocmVzaWR1YWxzLCBkaWFnbm9zdGljIHBsb3RzLCBldGMuKS4gIApgYGB7ciBleHBsb3JlX2dsbXNfZW52X2Z1bGxfc2FuZH0KIyMgcmVzaWR1YWxzIHZzIGZpdHRlZCB2YWx1ZXMKcGxvdChlbnYuZ2xtcy5zYW5kKQoKCiMjIGFsbCB0cmFkaXRpb25hbCAoZylsbSBkaWFnbm9zdGljIHBsb3RzCnBsb3QubWFueWdsbShlbnYuZ2xtcy5zYW5kLCB3aGljaCA9IDE6MykKCgojICMjIyBzb3VyY2UgbXZhYnVuZCBHTE0gcGxvdHRpbmcgZnVuY3Rpb25zIG1vZGlmaWVkIHRvIHVzZSBhIGdyZXkgcGFsZXR0ZSAtIEkganVzdCBjYW4ndCByZWRvIHRoZXNlIHBsb3RzIG9uIG15IG93biwgdGhlIGZ1bmN0aW9uIGlzIGRvaW5nIHRvbyBjb21wbGljYXRlZCB0aGluZ3MgaW50ZXJuYWxseSB0byBzY2FsZSB0aGUgeCBhbmQgeSBheGVzCiMgc291cmNlKGhlcmUoZnVuY3Rpb25zLmRpciwgImRlZmF1bHQucGxvdC5tYW55Z2xtX2dyZXkuUiIpKQojIHNvdXJjZShoZXJlKGZ1bmN0aW9ucy5kaXIsICJwbG90Lm1hbnlnbG1fZ3JleS5SIikpCiMgCiMgcGFyKG1mcm93ID0gYygyLDIpKQojIGxhcHBseSgxOjMsIGZ1bmN0aW9uKGkpIHBsb3QubWFueWdsbS5ncmV5KGdsbXMubHZtLnNhbmQsIHdoaWNoID0gaSwgc3ViLmNhcHRpb24gPSAiIikpCiMgcGFyKG1mcm93ID0gYygxLCAxKSkKCmBgYAoKV2VsbCwgaXQncyBnb29kIGVub3VnaCBpZiB5b3UgYXNrIG1lIChzdGlsbCB0aGUga2luZGEgc3RyYW5nZSAibGluZSIgYXQgbGluLnByZWQgPSAtNjsgb3RoZXJ3aXNlIHJlc2lkdWFscyBhcmUgcmFuZG9tIGVub3VnaCkuICAKClNhdmUgdGhlIG1vZGVsISAgCmBgYHtyIHNhdmVfZ2xtc19lbnZfZnVsbF9zYW5kfQp3cml0ZV9yZHMoZW52LmdsbXMuc2FuZCwgCiAgICAgICAgICBoZXJlKHNhdmUuZGlyLCAiZ2xtc19lbnZfc2FuZC5SRFMiKSkKYGBgCgoKQmVmb3JlIGFueXRoaW5nIGVsc2UsIEkgd2FudCB0byB0cnkgYW5kIHJlZHVjZSB0aGUgbW9kZWwgYSBsaXR0bGUgLSB0byBpbXByb3ZlIHRoZSBmaXQvcmVkdWNlIHJ1biB0aW1lLiAgClRoZSBhdXRvbWF0aWMgc3RlcCBmdW5jdGlvbnMgdGhhdCBlbGltaW5hdGUvYWRkIG1vZGVsIHRlcm1zIHNlcXVlbnRpYWxseSBkb24ndCB3b3JrIC0gdGhleSBmYWlsIGF0IHRoZSBsYXN0IHN0ZXAgd2l0aCBhIGNyeXB0aWMgZXJyb3IgYWJvdXQgZGlmZmVyaW5nIG51bWJlcnMgb2Ygcm93cyAtIEkgYXNzdW1lIGJlY2F1c2UgbWFueWdsbSBoYXMgYXMgbGVmdCBzaWRlIHRlcm0gdGhlIHdob2xlIGNvbW11bml0eSBhYnVuZGFuY2UgbWF0cml4LCBhbmQgdGhlIGZ1bmN0aW9ucyBkb24ndCByZWFsbHkga25vdyBob3cgdG8gZGVhbCB3aXRoIHRoYXQuIEkgZG9uJ3QgdW5kZXJzdGFuZCBlbm91Z2ggYWJvdXQgdGhlaXIgaW50ZXJuYWxzIHRvIGZpeCB0aGUgcHJvYmxlbSwgc28gSSdtIGp1c3QgZ29pbmcgdG8gd3JpdGUgbXkgb3duIGxpdHRsZSBhdXRvbWF0aW9uIGJhc2VkIG9uIHRoZSBmdW5jdGlvbiBkcm9wMS4gIApgYGB7ciBldmFsdWF0ZV9nbG1zX2Vudl9mdW5jdGlvbn0KZXZhbHVhdGVfZ2xtc19lbnYgPC0gZnVuY3Rpb24oZnVsbC5tb2QpIHsKICAjIyMgc2VxdWVudGlhbGx5IGVsaW1pbmF0ZSBtb2RlbCB0ZXJtcyBpbiBtYW55Z2xtcyB2cyBlbnZpcm9ubWVudGFsIHBhcmFtZXRlcnMsIGFuZCBmaW5kIHRoZSBiZXN0IG1vZGVsIGJhc2VkIG9uIGxvd2VzdCBBSUMgc2NvcmUuCiAgIyMjIEFyZ3VtZW50czogZnVsbC5tb2QgLSBmdWxsIG1vZGVsIGZpdAogICMjIyBSZXR1cm5zOiBiZXN0IG1hbnlnbG0gbW9kZWwgb2YgZW52aXJvbm1lbnRhbCBwYXJhbWV0ZXJzOyBwcmludHMgb3V0IHRoZSBiZXN0IG1vZGVsIGZvcm11bGEKICAjIyMgRGVwZW5kZW5jaWVzOiB0aWR5dmVyc2UgICAKICAKCiAgIyMgZ2V0IHRoZSBzdGFydGluZyBmb3JtdWxhICg9IGZ1bGwgbW9kZWwgd2l0aCBhbGwgdmFyaWFibGVzKQogIHN0YXJ0LmZvcm11bGEgPC0gZm9ybXVsYShmdWxsLm1vZCkKCiAgZHJvcF92YXIgPC0gZnVuY3Rpb24obW9kKSB7CiAgICAjIyMgaGVscGVyIHBpY2tpbmcgdGhlIG5leHQgdmFyaWFibGUgdG8gZHJvcCBmcm9tIGEgbW9kZWwgdG8gaW1wcm92ZSB0aGUgZml0IChiYXNlZCBvbiBBSUMpCiAgICAKICAgICMjIGNoZWNrIHRoZSBtb2RlbCBBSUNzIGlmIHZhcmlhYmxlcyBhcmUgZHJvcHBlZCBvbmUgYnkgb25lCiAgICBkcm9wMS5kZiA8LSBhc190aWJibGUoZHJvcDEobW9kKSwgcm93bmFtZXMgPSAiZHJvcF92YXIiKSAlPiUgYXJyYW5nZShBSUMpCiAgICAKICAgICMjIHBpY2sgdGhlIHZhcmlhYmxlIHRvIGRyb3AgbmV4dCAtIHRoZSBvbmUgcmVzdWx0aW5nIGluIHRoZSBsYXJnZXN0IGRlY3JlYXNlIGluIEFJQwogICAgZHJvcC52YXIgPC0gZHJvcDEuZGYgJT4lIGZpbHRlcihBSUMgPT0gbWluKEFJQykpICU+JSBwdWxsKGRyb3BfdmFyKQogICAgcmV0dXJuKGRyb3AudmFyKQogIH0KICAKICAjIyBwaWNrIHRoZSB2YXJpYWJsZSB0byBkcm9wIG5leHQKICBkcm9wLnZhciA8LSBkcm9wX3ZhcihmdWxsLm1vZCkKCiAgaWYoZHJvcC52YXIgIT0gIjxub25lPiIpIHsKICAgICAjIyB1cGRhdGUgdGhlIG1vZGVsIGZvcm11bGEsIGRyb3BwaW5nIHRoZSB2YXJpYWJsZSByZXN1bHRpbmcgaW4gdGhlIGxhcmdlc3QgZGVjcmVhc2UgaW4gQUlDOyB0aGVuIGFwcGx5IGl0IHRvIHRoZSBtb2RlbC4KICAgIG5ldy5mb3JtdWxhIDwtIHVwZGF0ZS5mb3JtdWxhKHN0YXJ0LmZvcm11bGEsIHBhc3RlMCgifi4gLSIsIGRyb3AudmFyKSkKICAgIG5ldy5tb2QgPC0gdXBkYXRlKGZ1bGwubW9kLCBuZXcuZm9ybXVsYSkKCiAgICAjIyBpZGVudGlmeSBhIG5ldyB2YXJpYWJsZSB0byBkcm9wIHRoYXQgbG93ZXJzIHRoZSBBSUMKICAgIGRyb3AudmFyIDwtIGRyb3BfdmFyKG5ldy5tb2QpCiAgICAKICAgICMjIHJlcGVhdCB0aGUgc3RlcHMgYWJvdmUgdW50aWwgdGhlIGZ1bmN0aW9uIGNhbiBubyBsb25nZXIgZmluZCBzdWNoIGEgdmFyaWFibGUgKGkuZS4sIGRyb3BwaW5nIG1vcmUgdmFyaWFibGVzIGRvZXNuJ3QgaW1wcm92ZSB0aGUgbW9kZWwgZml0KQogICAgd2hpbGUoZHJvcC52YXIgIT0gIjxub25lPiIpIHsKICAgICAgbmV3LmZvcm11bGEgPC0gdXBkYXRlLmZvcm11bGEobmV3LmZvcm11bGEsIHBhc3RlMCgifi4gLSIsIGRyb3AudmFyKSkKICAgICAgbmV3Lm1vZCA8LSB1cGRhdGUoZnVsbC5tb2QsIG5ldy5mb3JtdWxhKQogICAgICBkcm9wLnZhciA8LSBkcm9wX3ZhcihuZXcubW9kKQogICAgfQogICAgCiAgICAjIyBwcmludCBvdXQgdGhlIGJlc3QgbW9kZWwgZm9ybXVsYQogICAgcHJpbnQocGFzdGUoIkJlc3QgbW9kZWw6ICIsIHBhc3RlKGRlcGFyc2UobmV3LmZvcm11bGEpLCBjb2xsYXBzZSA9ICIiKSkpCiAgICByZXR1cm4obmV3Lm1vZCkKICAgIAogIH0gZWxzZSB7CiAgICAjIyBpZiB0aGUgc3RhcnRpbmcgbW9kZWwgaXMgdGhlIGJlc3QsIHByaW50IGl0cyBmb3JtdWxhIChmYXQgY2hhbmNlISkKICAgIHByaW50KHBhc3RlKCJCZXN0IG1vZGVsOiAiLCBwYXN0ZShkZXBhcnNlKHN0YXJ0LmZvcm11bGEpLCBjb2xsYXBzZSA9ICIiKSkpCiAgICByZXR1cm4oZnVsbC5tb2QpCiAgfQogIAp9CgpgYGAKCgpTZWxlY3QgdGhlIGJlc3QgcmVkdWNlZCBtb2RlbCBvZiBlbnZpcm9ubWVudGFsIHZhcmlhYmxlcyBmb3IgdGhlIHNhbmQgc3RhdGlvbnMuICAKYGBge3Igc2VsZWN0X3RvcF9nbG1fZW52X3NhbmR9CnRvcC5lbnYuZ2xtLnJlZC5zYW5kIDwtIGV2YWx1YXRlX2dsbXNfZW52KGVudi5nbG1zLnNhbmQpCgpgYGAKCkNoZWNrIGl0cyBmaXQuIApgYGB7ciBleHBsb3JlX3RvcF9nbG1fZW52X3JlZF9zYW5kfQojIyByZXNpZHVhbHMgdnMgZml0dGVkIHZhbHVlcwpwbG90KHRvcC5lbnYuZ2xtLnJlZC5zYW5kKQoKIyMgYWxsIHRyYWRpdGlvbmFsIChnKWxtIGRpYWdub3N0aWMgcGxvdHMKcGxvdC5tYW55Z2xtKHRvcC5lbnYuZ2xtLnJlZC5zYW5kLCB3aGljaCA9IDE6MykKYGBgCgpJIHRoaW5rIGl0J3MgZmluZTsgbWlnaHQgZXZlbiBiZSBiZXR0ZXIgdGhhbiB0aGUgZnVsbCBtb2RlbC4uIApTYXZlIGl0LCB0b28uIApgYGB7ciBzYXZlX3RvcF9nbG1fZW52X3JlZF9zYW5kfQp3cml0ZV9yZHModG9wLmVudi5nbG0ucmVkLnNhbmQsIAogICAgICAgICAgaGVyZShzYXZlLmRpciwgImdsbXNfdG9wX2Vudl9yZWRfc2FuZC5SRFMiKSkKYGBgCgoKUnVuIEFOT1ZBIG9uIHRoaXMgbW9kZWwuCmBgYHtyIGFub3ZhX3RvcF9nbG1fZW52X3JlZF9zYW5kfQoodG9wLmVudi5nbG0ucmVkLnNhbmQuYW92IDwtIGFub3ZhLm1hbnlnbG0odG9wLmVudi5nbG0ucmVkLnNhbmQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZXN0ID0gIkxSIiwgcC51bmkgPSAiYWRqdXN0ZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbkJvb3QgPSA5OTksICMjIGxpbWl0IHRoZSBudW1iZXIgb2YgcGVybXV0YXRpb25zIGZvciBhIHNob3J0ZXIgcnVuIHRpbWUgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNob3cudGltZSA9ICJhbGwiKSAKKQpgYGAKClNvLCBpdCB0dXJucyBvdXQgdGhhdCB0aGUgbG9uZy10ZXJtIHdhdGVyIGNvbHVtbiBldXRyb3BoaWNhdGlvbiAoUE80LCBzZXN0b24pLCB0aGUgYW50aHJvcG9nZW5pYyBwcmVzc3VyZSBpbiBnZW5lcmFsIChMVVNJKSwgYW5kIHRoZSBzZWRpbWVudCBjb21wb3NpdGlvbiAoZ3JhdmVsKSBleHBsYWluIHRoZSBvYnNlcnZlZCBjb21tdW5pdHkgcGF0dGVybnMgYmVzdC4gCgpTYXZlIHRoZSBBTk9WQSAtIEkgcmVhbGx5LCByZWFsbHkgZG9uJ3Qgd2FudCB0byBoYXZlIHRvIHJlcGVhdCBpdC4gIApgYGB7ciBzYXZlX2Fub3ZhX3RvcF9nbG1fZW52X3JlZF9zYW5kfQp3cml0ZV9yZHModG9wLmVudi5nbG0ucmVkLnNhbmQuYW92LCAKICAgICAgICAgIGhlcmUoc2F2ZS5kaXIsICJnbG1zX3RvcF9lbnZfcmVkX3NhbmRfYW5vdmEuUkRTIikpCmBgYAoKR2V0IHRoZSB0YXhhIHdpdGggdGhlIGhpZ2hlc3QgY29udHJpYnV0aW9ucyB0byB0aGUgdGVzdGVkIHBhdHRlcm4gKGhlcmUgLSBzcGVjaWVzIG1vc3QgYWZmZWN0ZWQgYnkgY2hhbmdlcyBpbiB3YXRlci9lbnZpcm9ubWVudGFsIHF1YWxpdHkgcGFyYW1ldGVycykuICAKYGBge3IgcmVsYXRpdmVfdGF4b25fY29udHJpYl90b3BfZ2xtX2Vudl9yZWRfc2FuZH0KIyMgZ2V0IHRoZSB0b3AgY29udHJpYnV0aW5nIHNwZWNpZXMgZm9yIHRoZSBlbnZpcm9ubWVudGFsIHBhcmFtZXRlciBzYW5kIEdMTXMgCih0b3Auc3AuZ2xtcy5lbnYucmVkLnNhbmQgPC0gdG9wX25fc3BfZ2xtKHRvcC5lbnYuZ2xtLnJlZC5zYW5kLmFvdiwgdG90LmRldi5leHBsID0gMC43NSkKKQoKIyMgdW5mb3J0dW5hdGVseSwgbXZhYnVuZCBsaWtlcyB0byByZW5hbWUgbXkgc3BlY2llcyB3aGVuIGNvbnZlcnRpbmcgdGhlIGRhdGEgdG8gbWF0cml4IChubyBzcGFjZXMgaW4gbmFtZXMpLCBhbmQgc2luY2UgSSdtIGdvaW5nIHRvIGxvb2sgdGhlbSB1cCBpbiBteSBpbml0aWFsIHVudHJhbnNmb3JtZWQgY291bnQgZGF0YSwgSSBoYXZlIHRvIGNoYW5nZSB0aGVtIGJhY2suLiAgIERPTidUIEJFIElOIEEgSFVSUlkgVE8gRE8gVEhBVCBJRiBZT1UgV0FOVCBUTyBTVUJTRVQgVEhFIE9SSUdJTkFMIE1BVFJJWCBCRUZPUkUgUlVOTklORyBUUkFJVEdMTSAKbmFtZXModG9wLnNwLmdsbXMuZW52LnJlZC5zYW5kKSA8LSBuYW1lcyh0b3Auc3AuZ2xtcy5lbnYucmVkLnNhbmQpICU+JSAKICBzdHJfcmVwbGFjZShwYXR0ZXJuID0gIlxcLiIsIHJlcGxhY2VtZW50ID0gIiAiKQoKYGBgCgpJJ20gZ29pbmcgdG8gcGxvdCB0aGVzZSB0b3AgY29udHJpYnV0aW5nIHNwZWNpZXMsIGJ1dCBJJ20gbm90IHVzaW5nIHRoZSBwbG90LiBBdCBsZWFzdCB0aGlzIHRpbWUgaXQncyBtb3JlIG1hbmFnZWFibGUsIGJ1dCBzdGlsbCBub3QgcHJlc2VudGFibGUgZW5vdWdoLi4gCgpgYGB7ciBwbG90X3JlbGF0aXZlX3RheG9uX2NvbnRyaWJfdG9wX2dsbV9lbnZfcmVkX3NhbmR9CiMjIGdldCB0aGUgc3BlY2llcyBhbmQgdGhlaXIgYWJ1bmRhbmNlcyBmcm9tIHRoZSBvcmlnaW5hbCBjb3VudCBkYXRhLCBhbmQgdHJhbnNmb3JtIHRoZW0gdG8gbG9uZyBmb3JtYXQKYWJuZC50b3Auc3AuZ2xtcy5lbnYucmVkLnNhbmQgPC0gem9vLmFibmQuc2FuZCAlPiUgCiAgc2VsZWN0KHN0YXRpb24sIG5hbWVzKHRvcC5zcC5nbG1zLmVudi5yZWQuc2FuZCkpICU+JSAKICBnYXRoZXIoa2V5ID0gInNwZWNpZXMiLCB2YWx1ZSA9ICJjb3VudCIsIC1zdGF0aW9uKSAlPiUgCiAgIyMgdHVybiBzcGVjaWVzIGludG8gYSBmYWN0b3IsIG9yIHlvdSdsbCBiZSB2ZXJ5IHZlcnkgc29ycnkgbGF0ZXIsIHdoZW4gdGhleSdyZSBvdXQgb2Ygb3JkZXIgb24gdGhlIHBsb3QuIE5CIG5lZWQgdG8gYmUgaW4gUkVWRVJTRSBvcmRlciwgYmVjYXVzZSBnZ3Bsb3QgcGxvdHMgZnJvbSBib3R0b20gdG8gdG9wLCBhbmQgSSB3YW50IHRoZSB0b3AtY29udHJpYnV0aW5nIHNwZWNpZXMgb24gdG9wLiAKICBtdXRhdGUoc3BlY2llcyA9IGZhY3RvcihzcGVjaWVzLCBsZXZlbHMgPSByZXYobmFtZXModG9wLnNwLmdsbXMuZW52LnJlZC5zYW5kKSkpKSAlPiUgCiAgIyMgYWRkIGNsdXN0ZXJzIGZyb20gTFZNIGFzIGEgY29sdW1uCiAgbXV0YXRlKGdyb3VwID0gY2FzZV93aGVuKHN0YXRpb24gJWluJSBjKCJLcmFpbW9yaWUiLCAiQ2h1a2FseWEiKSB+IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXRpb24gPT0gIkFraW4iIH4gMiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXRpb24gJWluJSBjKCJTb3pvcG9sIiwgIlBhcmFza2V2YSIpIH4gMywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXRpb24gPT0gIkFnYWxpbmEiIH4gNCkpCgoKCiMjIGFkZCB0aGUgc2lnbmlmaWNhbnQgZW52aXJvbm1lbnRhbCBwYXJhbWV0ZXJzIGZyb20gdGhlIG1vZGVsCihhYm5kLnRvcC5zcC5nbG1zLmVudi5yZWQuc2FuZCA8LSBsZWZ0X2pvaW4oYWJuZC50b3Auc3AuZ2xtcy5lbnYucmVkLnNhbmQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVudi5zYW5kICU+JSBzZWxlY3Qoc3RhdGlvbiwgUE80LCBzZXN0b24sIExVU0ksIGdyYXZlbCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gInN0YXRpb24iKSAKICAgIAopCgoKKHBsb3QudG9wLnNwLmdsbXMuZW52LnJlZC5zYW5kIDwtIHBsb3RfdG9wX24oYWJuZC50b3Auc3AuZ2xtcy5lbnYucmVkLnNhbmQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IHNwZWNpZXMsIHkgPSBsb2dfeV9taW4oY291bnQpLCBjb2xvdXIgPSBmYWN0b3IoZ3JvdXApKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFicy5sZWdlbmQgPSB1bmlxdWUoYWJuZC50b3Auc3AuZ2xtcy5lbnYucmVkLnNhbmQkZ3JvdXApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWIueSA9ICJBYnVuZGFuY2UgKGxvZyh5L21pbiArIDEpKSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhbGV0dGUgPSAiU2V0MiIpICsgCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikKKQpgYGAKCkZJWE1FPj4+ClRyeSBhbm90aGVyIHRoaW5nIC0gbWFudWFsbHksIHVuZm9ydHVuYXRlbHk6IHRoaXMgc2FtZSBuaWdodG1hcmUsIGJ1dCBjb2xvcmVkIGJ5IHRoZSB2YWx1ZXMgb2YgZWFjaCBtb2RlbCB0ZXJtLiAKYGBge3IgY29tcG9zaXRlX3Bsb3RfcmVsYXRpdmVfdGF4b25fY29udHJpYl90b3BfZ2xtX2Vudl9zYW5kfQpnZ3Bsb3QoYWJuZC50b3Auc3AuZ2xtcy5lbnYucmVkLnNhbmQsCiAgICAgICBtYXBwaW5nID0gYWVzKHggPSBzcGVjaWVzLCB5ID0gbG9nX3lfbWluKGNvdW50KSwgY29sb3VyID0gZ3JhdmVsKSkgKyAKICBnZW9tX3BvaW50KCkgKyAKICBjb29yZF9mbGlwKCkKYGBgCgoKCkV4dHJhY3QgdGhlIHRheG9uIGluZm9ybWF0aW9uICh1bml2YXJpYXRlIHRlc3RzKSBmcm9tIHRoZSBtb2RlbCBBTk9WQSB0byBwcmVzZW50IGFzIGEgdGFibGUgKHByb2JhYmx5IGJldHRlciB0aGFuIHRoaXMgcGxvdCwgYWx0aG91Z2ggaXQncyBpbmZvcm1hdGl2ZSkuICAKYGBge3IgdGFibGVfcmVsYXRpdmVfdGF4b25fY29udHJpYl90b3BfZ2xtX2Vudl9yZWRfc2FuZH0KIyMgZXh0cmFjdCB0aGUgdW5pdmFyaWF0ZSB0ZXN0IGNvZWZmaWNpZW50cyAoTFIpIGZyb20gdGhlIGVudmlyb25tZW50YWwgbW9kZWwgQU5PVkEuIE5CIGtlZXAgdGhlIHJvdyBuYW1lcyB3aGVuIGNvbnZlcnRpbmcgdGhlIG1hdHJpeCB0byB0aWJibGUhIAp0YWJsZS50b3Auc3AuZ2xtcy5lbnYucmVkLnNhbmQgPC0gYXNfdGliYmxlKHRvcC5lbnYuZ2xtLnJlZC5zYW5kLmFvdiR1bmkudGVzdCwgcm93bmFtZXMgPSAidmFyIikKCiMjIGZpeCB0aGUgc3BlY2llcyBuYW1lcyAtIHJlbW92ZSBmaXJzdCBkb3QgIApuYW1lcyh0YWJsZS50b3Auc3AuZ2xtcy5lbnYucmVkLnNhbmQpIDwtIG5hbWVzKHRhYmxlLnRvcC5zcC5nbG1zLmVudi5yZWQuc2FuZCkgJT4lIAogIHN0cl9yZXBsYWNlKHBhdHRlcm4gPSAiXFwuIiwgcmVwbGFjZW1lbnQgPSAiICIpCgojIyBzdWJzZXQgb25seSB0aGUgdG9wIHNwZWNpZXMgKGV4cGxhaW5pbmcgfjc1JSBvZiB0aGUgZGF0YXNldCB2YXJpYXRpb24pCnRhYmxlLnRvcC5zcC5nbG1zLmVudi5yZWQuc2FuZCA8LSB0YWJsZS50b3Auc3AuZ2xtcy5lbnYucmVkLnNhbmQgJT4lIAogIHNlbGVjdCh2YXIsIG5hbWVzKHRvcC5zcC5nbG1zLmVudi5yZWQuc2FuZCkpCgojIyB0cmFuc3Bvc2UsIGJlY2F1c2UgYSB0YWJsZSB3aXRoIDUwIGNvbHVtbnMgaXMganVzdCB1bnJlYWRhYmxlCih0YWJsZS50b3Auc3AuZ2xtcy5lbnYucmVkLnNhbmQgPC0gdGFibGUudG9wLnNwLmdsbXMuZW52LnJlZC5zYW5kICU+JQogICAgZ2F0aGVyKGtleSA9IHNwZWNpZXMsIHZhbHVlID0gdmFsdWUsIC12YXIpICU+JSAKICAgIHNwcmVhZChrZXkgPSB2YXIsIHZhbHVlID0gdmFsdWUpICU+JSAKICAgICMjIGFycmFuZ2UgYXMgYmVmb3JlICh0ZXJtcyBpbiB0aGUgb3JkZXIgdGhleSBhcHBlYXIgaW4gdGhlIG1vZGVsLCBhbmQgYnkgZGVzY2VuZGluZyB2YWx1ZSBvZiB0aGUgTFIgZm9yIHRoZSBmaXJzdCBtb2RlbCB0ZXJtIC0gaGVyZSwgUE80KS4gQWxzbyBnZXQgcmlkIG9mIHRoZSBpbnRlcmNlcHQgKGl0J3MgYWxsLU5BIGFueXdheSkuCiAgICBzZWxlY3Qoc3BlY2llcywgUE80LCBzZXN0b24sIExVU0ksIGdyYXZlbCkgJT4lCiAgICBhcnJhbmdlKGRlc2MoUE80KSkgCikKYGBgCgpTYXZlIHRoaXMgdG8gYSBmaWxlIC0gd2lsbCBoYXZlIHRvIGZvcm1hdCBpdCBhcyBhIG5pY2UgdGFibGUgYnkgaGFuZCwgdW5mb3J0dW5hdGVseS4gCmBgYHtyIHNhdmVfdGFibGVfcmVsYXRpdmVfdGF4b25fY29udHJpYl90b3BfZ2xtX2Vudl9yZWRfc2FuZH0Kd3JpdGVfY3N2KHRhYmxlLnRvcC5zcC5nbG1zLmVudi5yZWQuc2FuZCwgCiAgICAgICAgICBoZXJlKHNhdmUuZGlyLCAidGF4YV9jb250cmliX2dsbXNfdG9wX2Vudl9yZWRfc2FuZC5jc3YiKSkKYGBgCgoKQ2FsY3VsYXRlIHRoZSBwZXJjZW50YWdlIGNvbnRyaWJ1dGlvbiBvZiBlYWNoIG9mIHRoZXNlIHNwZWNpZXMgdG8gZWFjaCBvZiB0aGUgbW9kZWwgdGVybXMgKERldih0ZXJtKSA9IFN1bS1vZi1MUiAtIHN1bSBvZiB0aGUgTFJzIGZvciB0aGUgaW5kaXZpZHVhbCB1bml2YXJpYXRlIHNwZWNpZXMgdGVzdHMpLi4gCmBgYHtyIHRhYmxlX3Byb3BfcmVsYXRpdmVfdGF4b25fY29udHJpYl90b3BfZ2xtX2Vudl9yZWRfc2FuZH0KIyMgZ2V0IHRoZSB0b3RhbCBkZXZpYW5jZSAoU3VtLW9mLUxSKSBmb3IgZWFjaCBtb2RlbCB0ZXJtCihkZXYudGVybXMudG9wLmdsbXMuZW52LnNhbmQgPC0gYXNfdGliYmxlKHRvcC5lbnYuZ2xtLnJlZC5zYW5kLmFvdiR0YWJsZSwgcm93bmFtZXMgPSAidmFyIikgJT4lCiAgICMjIGdldCByaWQgb2YgdW5uZWNlc3NhcnkgdmFyaWFibGVzIChJIG9ubHkgd2FudCB0aGUgZGV2aWFuY2UgdmFsdWUgZm9yIGVhY2ggdGVybSkgYW5kIGludGVyY2VwdCB0ZXJtIAogICBzZWxlY3QodmFyLCBEZXYpICU+JSAKICAgZmlsdGVyKHZhciAhPSAiKEludGVyY2VwdCkiKSAlPiUgCiAgICMjIHRyYW5zcG9zZSAKICAgZ2F0aGVyKHZhcmlhYmxlLCB2YWx1ZSwgLXZhcikgJT4lCiAgIHNwcmVhZCh2YXIsIHZhbHVlKSAlPiUgCiAgICMjIGdldCByaWQgb2YgZmlyc3QgY29sdW1uIGFuZCByZWFycmFuZ2UgY29sdW1ucyB0byBtYXRjaCB0YWJsZSBvZiBkZXZpYW5jZXMgb2YgdW5pdmFyaWF0ZSB0ZXN0cyBmb3Igc3BlY2llcyAKICAgc2VsZWN0KC12YXJpYWJsZSkgJT4lIAogICBzZWxlY3QoUE80LCBzZXN0b24sIExVU0ksIGdyYXZlbCkKKSAgCgojIyBjYWxjdWxhdGUgdGhlIHByb3BvcnRpb24gY29udHJpYnV0aW9uIG9mIGVhY2ggc3BlY2llcyB0byBlYWNoIHBhcmFtZXRlciBkZXZpYW5jZQpwcm9wLnRvcC5zcC5nbG1zLmVudi5yZWQuc2FuZCA8LSBtYXAyX2RmKHRhYmxlLnRvcC5zcC5nbG1zLmVudi5yZWQuc2FuZCAlPiUgc2VsZWN0KC1zcGVjaWVzKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZXYudGVybXMudG9wLmdsbXMuZW52LnNhbmQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH4ueC8ueSkKCiMjIGFkZCBiYWNrIHRoZSBzcGVjaWVzIAoocHJvcC50b3Auc3AuZ2xtcy5lbnYucmVkLnNhbmQgPC0gYmluZF9jb2xzKHRhYmxlLnRvcC5zcC5nbG1zLmVudi5yZWQuc2FuZCAlPiUgc2VsZWN0KHNwZWNpZXMpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9wLnRvcC5zcC5nbG1zLmVudi5yZWQuc2FuZCkKKQoKYGBgCgoKRmluYWwgYW5hbHlzaXMgdG8gdHJ5OiB3aGljaCBzcGVjaWVzIHJlc3BvbmQgZGlmZmVyZW50bHkgdG8gZGlmZmVyZW50IGVudmlyb25tZW50YWwgcGFyYW1ldGVycz8KKD0gdHJhaXRzIGFuYWx5c2lzIC0gZml0IHNpbmdsZSBwcmVkaWN0aXZlIG1vZGVsIGZvciBhbGwgc3BlY2llcyBhdCBhbGwgc2l0ZXMsIGJ1dCB3L28gYXR0ZW1wdGluZyB0byBleHBsYWluIHRoZSBkaWZmZXJlbnQgcmVzcG9uc2VzIHVzaW5nIHRyYWl0cyAtIHRoZSBzcGVjaWVzIElEIGlzIHVzZWQgaW4gcGxhY2Ugb2YgYSB0cmFpdHMgbWF0cml4KS4gIApOQiBvbmx5IHVzZSB0aGUgdG9wIHNwZWNpZXMgdGhhdCBleGhpYml0ZWQgYSByZWFjdGlvbiBpbiB0aGUgZW52aXJvbm1lbnRhbCBtb2RlbCBmaXQgKD0gdGhlIG9uZXMgYWNjb3VudGluZyBmb3Igfjc1JSBvZiB0aGUgdG90YWwgdmFyaWFiaWxpdHkpLCBhbmQgb25seSB0aGUgc2lnbmlmaWNhbnQgcHJlZGljdG9ycyAtIHRvIGltcHJvdmUgcnVuIHRpbWVzLiAgIApgYGB7ciBzcF9yZXNwb25zZV90b3BfZ2xtX2Vudl9yZWRfc2FuZH0Kc3AucmVzcG9uc2UuZ2xtcy5lbnYucmVkLnNhbmQgPC0gdHJhaXRnbG0oTCA9IG12YWJ1bmQoem9vLmFibmQuZmx0LnNhbmRbLCBuYW1lcyh0b3Auc3AuZ2xtcy5lbnYucmVkLnNhbmQpXSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBSID0gYXMubWF0cml4KGVudi5zYW5kICU+JSBzZWxlY3QoUE80LCBzZXN0b24sIExVU0ksIGdyYXZlbCkpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0aG9kID0gIm1hbnlnbG0iKQoKCnNwLnJlc3BvbnNlLmdsbXMuZW52LnJlZC5zYW5kJGZvdXJ0aC5jb3JuZXIKCgojIHBsb3QgdGhpcyAKYSA8LSBtYXgoYWJzKHNwLnJlc3BvbnNlLmdsbXMuZW52LnJlZC5zYW5kJGZvdXJ0aC5jb3JuZXIpKQpjb2xvcnQgPC0gY29sb3JSYW1wUGFsZXR0ZShjKCJibHVlIiwid2hpdGUiLCJyZWQiKSkgCnBsb3Quc3BwIDwtIGxhdHRpY2U6OmxldmVscGxvdCh0KGFzLm1hdHJpeChzcC5yZXNwb25zZS5nbG1zLmVudi5yZWQuc2FuZCRmb3VydGguY29ybmVyKSksIHhsYWIgPSAiRW52aXJvbm1lbnRhbCBWYXJpYWJsZXMiLAogICAgICAgICAgICAgICAgICAgICB5bGFiID0gIlNwZWNpZXMiLCBjb2wucmVnaW9ucyA9IGNvbG9ydCgxMDApLCBhdCA9IHNlcSgtYSwgYSwgbGVuZ3RoID0gMTAwKSwKICAgICAgICAgICAgICAgICAgICAgc2NhbGVzID0gbGlzdCh4ID0gbGlzdChyb3QgPSA0NSkpKQpwcmludChwbG90LnNwcCkKYGBgCgpXaGVuIHVzaW5nIExBU1NPIChtZXRob2QgPSAiZ2xtMXBhdGgiKSwgdGhlIGFsZ29yaXRobSBmYWlscyB0byBjb252ZXJnZSAtIEknbSBub3Qgc3VyZSBob3cgdG8gaW50ZXJwcmV0IGl0Li4gTWF5YmUgYmVjYXVzZSB0aGUgZnVuY3Rpb24gdGVzdHMgZWFjaCBpbmRpdmlkdWFsIHNwZWNpZXM6ZW52LnBhcmFtZXRlciBpbnRlcmFjdGlvbiAoZG9lcyBpdCByZWFsbHk/PyksIGFuZCBub25lIG9mIHRoZW0gYnkgdGhlbXNlbHZlcyBhcmUgc3VmZmljaWVudCB0byBleHBsYWluIGEgc3BlY2llcycgcmVzcG9uc2UuIE5vdCB0byBtZW50aW9uIHRoZSBmYWN0IHRoYXQgdGhlIHNhbXBsZXMgYXJlIG5vdCByZWFsbHkgaW5kZXBlbmRlbnQgKHRoZXkgYXJlIHJlcGxpY2F0ZXMgYXQgNiBzaXRlcywgcmVwZWF0ZWQgMyB0aW1lcykuICAKV2hlbiB1c2luZyBtZXRob2QgPSAibWFueWdsbSIsIHRoZSByZXN1bHQgaXMgdGhlIG9uZSBzaG93biBhYm92ZS4gSXQncyBzdGlsbCBhIGJpdGNoIHRvIGludGVycHJldCAtIGZvciBleGFtcGxlLCB3aGF0IGlzIHRoZSBpbnRlcnByZXRhdGlvbiBvZiBhbiBpbmNyZWFzZSBpbiBhYnVuZGFuY2Ugd2l0aCBmb3IgZXguIGhpZ2ggUE80LCBidXQgbG93IExVU0k/IFdoZXJlIGFyZSB0aGVzZSBjb25kaXRpb25zIGV2ZXIgbWV0PyAgIAoKSW4gZmFjdCwgZXZlcnl0aGluZyBwb2ludHMgdG93YXJkcyB0aGUgY29uY2x1c2lvbiB0aGF0IGEgc3BlY2llcyByZXNwb25zZSBpcyBkZXRlcm1pbmVkIGJ5IGEgY29tYmluYXRpb24gb2YgZXV0cm9waGljYXRpb24gcGFyYW1ldGVycyBpbiBpdHMgZW52aXJvbm1lbnQgKHdhdGVyIGNvbHVtbiBjaGFyYWN0ZXJpc3RpY3MpLCBhbmQgdGhlIGNvbXBvc2l0aW9uIG9mIHRoZSBzZWRpbWVudHMgKG9yZ2FuaWMgbWF0dGVyIGFuZCBncmFudWxvbWV0cnkpLiAgCgpUaGlzIGlzIGFjdHVhbGx5IHNvcnQgb2Ygc2ltaWxhciB0byB0aGUgUEVSTUFOT1ZBIHJlc3VsdHMsIGluIHRoaXMgcGFydGljdWxhciBjYXNlLiBIb3dldmVyLCBpdCdzIG11Y2ggbW9yZSBwYXJzaW1vbmlvdXMuICAKSW4gdGhlIGZ1dHVyZSwgSSdtIGxlYW5pbmcgbW9yZSB0b3dhcmRzIHRoZSBtb2RlbGluZyBhcHByb2FjaCAtIGl0IGFsbG93cyB5b3UgdG8gY2hlY2sgdGhlIG1vZGVsIGZpdCB0byBvbmUncyByZWFsIGRhdGE7IGFsc28sIHRoZXJlIGFyZSBubyBkYXRhIHJlZHVjdGlvbnMgZHVlIHRvIGNhbGN1bGF0aW9uIG9mIGRpc3RhbmNlIG1hdHJpY2VzLiAgCgoKCiMjIyMgKipTZWFncmFzcyBzdGF0aW9ucyAoQnVyZ2FzIEJheSwgMjAxMy0yMDE0KSoqICAKSW1wb3J0IHpvb2JlbnRoaWMgYWJ1bmRhbmNlIGRhdGEgKGNsZWFuZWQgYW5kIHByZXBhcmVkKS4gIApgYGB7ciBpbXBvcnRfem9vX2FibmRfem9zdGVyYX0Kem9vLmFibmQuem9zdGVyYSA8LSByZWFkX2NzdihoZXJlKHNhdmUuZGlyLCAiYWJuZF96b3N0ZXJhX29yaWdfY2xlYW4uY3N2IikpCgojIyBjb252ZXJ0IHN0YXRpb24gdG8gZmFjdG9yIChiZXR0ZXIgc2FmZSB0aGFuIHNvcnJ5IGxhdGVyLCB3aGVuIHRoZSBzdGF0aW9ucyBhcmUgbm90IHBsb3R0ZWQgaW4gdGhlIG9yZGVyIEkgd2FudCB0aGVtKQooem9vLmFibmQuem9zdGVyYSA8LSB6b28uYWJuZC56b3N0ZXJhICU+JSAKICAgIG11dGF0ZShzdGF0aW9uID0gZmFjdG9yKHN0YXRpb24sIGxldmVscyA9IGMoIlBvZGEiLCAiT3RtYW5saSIsICJWcm9tb3MiLCAiR3JhZGluYSIsICJSb3BvdGFtbyIpKSkKKQpgYGAKClJlbW92ZSB0aGUgYWxsLTAgc3BlY2llcyAoPSBub3QgcHJlc2VudCBpbiB0aGUgY3VycmVudCBkYXRhc2V0KS4gIApNYXliZSBhbHNvIHJlbW92ZSB0aGUgc2luZ2xldG9ucyAoc3BlY2llcyBhcHBlYXJpbmcgb25seSBvbmNlIGluIHRoZSB3aG9sZSBkYXRhc2V0IGFuZCByZXByZXNlbnRlZCBieSBhIHNpbmdsZSBpbmRpdmlkdWFsID0gc28gcmFyZSB0aGF0IGl0J3MgdW5saWtlbHkgdGhleSBjYXJyeSBpbXBvcnRhbnQgaW5mb3JtYXRpb24sIGJ1dCBpdCB3b3VsZCBwcm9iYWJseSBpbXByb3ZlIHRoZSBydW4gdGltZXMpLiAgCmBgYHtyIGZpbHRlcl96b29fZGF0YV96b3N0ZXJhfQooem9vLmFibmQuZmx0Lnpvc3RlcmEgPC0gem9vLmFibmQuem9zdGVyYSAlPiUKICAgc2VsZWN0KC1jKHN0YXRpb246cmVwbGljYXRlKSkgJT4lCiAgIHNlbGVjdCh3aGljaChjb2xTdW1zKC4pID4gMCkpCikKYGBgCgoKIyMjIyMgKipMVk0gLSBtb2RlbC1iYXNlZCBvcmRpbmF0aW9uKioKUGVyZm9ybSBhIG1vZGVsLWJhc2VkIHVuY29uc3RyYWluZWQgb3JkaW5hdGlvbiBieSBmaXRpbmcgYSBwdXJlIGxhdGVudCB2YXJpYWJsZSBtb2RlbCAocGFja2FnZSBib3JhbCAtIEh1aSBldCBhbC4sIDIwMTQpLiBUaGlzIHdpbGwgYWxsb3cgdG8gdmlzdWFsaXplIHRoZSBtdWx0aXZhcmlhdGUgc3RhdGlvbnMgeCBzcGVjaWVzIGRhdGEgLSBzaW1pbGFyIHRvIG5NRFMsIGNhbiBiZSBpbnRlcnByZXRlZCBpbiB0aGUgc2FtZSB3YXkuICAgCkknbSBpbmNsdWRpbmcgYSAoZml4ZWQpIHJvdyBlZmZlY3QgdG8gYWNjb3VudCBmb3IgZGlmZmVyZW5jZXMgaW4gc2l0ZSB0b3RhbCBhYnVuZGFuY2UgLSB0aGlzIHdheSwgdGhlIG9yZGluYXRpb24gaXMgaW4gdGVybXMgb2YgKipzcGVjaWVzIGNvbXBvc2l0aW9uKiouICAgCk5CIHRoaXMgdGFrZXMgYWJvdXQgYSBtaWxsaW9uIHllYXJzIHRvIHJ1biEgCmBgYHtyIGx2bV96b3N0ZXJhfQpsdm0uem9zdGVyYSA8LSBib3JhbCh5ID0gem9vLmFibmQuZmx0Lnpvc3RlcmEsIAogICAgICAgICAgICAgICAgICBmYW1pbHkgPSAibmVnYXRpdmUuYmlub21pYWwiLAogICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgIyMgd2Ugd2FudCB0byBjb250cm9sIGZvciBzaXRlIGVmZmVjdHMgLSB0aGVyZSBhcmUgNiBzaXRlcyB3aXRoIDkgcmVwbGljYXRlcyBlYWNoCiAgICAgICAgICAgICAgICAgIHJvdy5lZmYgPSAiZml4ZWQiLCByb3cuaWRzID0gbWF0cml4KHJlcCgxOjUsIHRpbWVzID0gYyg4LCA4LCA0LCA4LCA0KSksIG5jb2wgPSAxKSwgIAogICAgICAgICAgICAgICAgICAjIyAyIGxhdGVudCB2YXJpYWJsZXMgPSAyIGF4ZXMgb24gd2hpY2ggdG8gcmVwcmVzZW50IHRoZSB6b29iZW50aGljIGRhdGEKICAgICAgICAgICAgICAgICAgbHYuY29udHJvbCA9IGxpc3QobnVtLmx2ID0gMikgCiAgICAgICAgICAgICAgICAgIAogICAgICMgICAgICAgICAgICAgICMjIGV4YW1wbGUgY29udHJvbCBzdHJ1Y3R1cmUsIHRvIGNoZWNrIGlmIGZ1bmN0aW9uIGRvZXMgd2hhdCBJIHdhbnQsIGJlY2F1c2Ugb3RoZXJ3aXNlIGl0IHRha2VzIGFuIGludG9sZXJhYmx5IGxvbmcgdGltZSwgYW5kIEknbGwgc2hvb3QgbXlzZWxmIGlmIEkgaGF2ZSB0byB3YWl0IGZvciBpdCBhZ2FpbgogICAgICMgICAgICAgICAgICAgIG1jbWMuY29udHJvbCA9IGxpc3Qobi5idXJuaW4gPSAxMCwgbi5pdGVyYXRpb24gPSAxMDAsCiAgICAgIyBuLnRoaW4gPSAxKQogICAgICMgICAgICAgICAgICAgIAogICAgIAogICAgICAgICAgICAgICAgICApCgpgYGAKCkNoZWNrIHRoZSBzdW1tYXJ5IGFuZCBkaWFnbm9zdGljIHBsb3RzIGZvciB0aGUgTFZNLiAgCmBgYHtyIHN1bW1hcnlfbHZtX3pvc3RlcmF9CnN1bW1hcnkobHZtLnpvc3RlcmEpCgojIyBtb2RlbCBmaXQgZGlhZ25vc3RpYyBwbG90cwpwbG90KGx2bS56b3N0ZXJhKSAKYGBgClRoZSByZXNpZHVhbHMgcGxvdHMgbG9vayBmaW5lIChubyBwYXR0ZXJucyBpbiB0aGUgcmVzaWR1YWxzIHZzIGZpdHRlZCwgc28gdmFyaWFuY2UgaXMgaG9tb2dlbmVvdXMsIHRoZSBxdWFudGlsZSBwbG90IHNob3dzIGEgKG1vcmUgb3IgbGVzcykgbm9ybWFsIGRpc3RyaWJ1dGlvbiBvZiB0aGUgcmVzaWR1YWxzKSAtIHRoZSBtb2RlbCBmaXRzIHRoZSBkYXRhIHByZXR0eSB3ZWxsLiAgCgpTYXZlIHRoZSB6b3N0ZXJhIExWTS4gIApgYGB7ciBzYXZlX2x2bV96b3N0ZXJhfQp3cml0ZV9yZHMobHZtLnpvc3RlcmEsIAogICAgICAgICAgaGVyZShzYXZlLmRpciwgImx2bV96b3N0ZXJhLlJEUyIpKQpgYGAKCkV4YW1pbmUgdGhlIGJpcGxvdCBvYnRhaW5lZCBieSBmaXR0aW5nIHRoZSBMVk0sIGFzIHdlbGwgYXMgdGhlIDIwIG1vc3QgImltcG9ydGFudCIgc3BlY2llcy4gICAKYGBge3IgY2hlY2tfYmlwbG90X2x2bV96b3N0ZXJhfQpsdnNwbG90KGx2bS56b3N0ZXJhLCBqaXR0ZXIgPSBULCBiaXBsb3QgPSBUUlVFLCBpbmQuc3BwID0gMjApCmBgYAoKQWxsIGluIGFsbCwgdGhlIGZpbmFsIHJlc3VsdCByZXNlbWJsZXMgdGhlIG5NRFMgb3JkaW5hdGlvbiB2ZXJ5IG11Y2ggLSBzYW1lIHN0cmV0Y2hlZCBjbHVzdGVycyAoUG9kYSArIE90bWFubGksIFZyb21vcyBwcmV0dHkgbXVjaCBhcGFydCwgR3JhZGluYSArLSBSb3BvdGFtbykuIEkgZG9uJ3Qgc2VlIG11Y2ggZGlmZmVyZW5jZSB3aXRoIHRoZSBuTURTLiAKVGhlIG1haW4gZGlmZmVyZW5jZSBzZWVtcyB0byBiZSB0aGUgZGlzdGFuY2UgYmV0d2VlbiB0aGUgMiB5ZWFycyBmb3IgUG9kYSBhbmEgT3RtYW5saSAtIHRoZSBMVk0gZW5sYXJnZXMgaXQuIEhhdmUgdG8gcmVtZW1iZXIgdG8gdGVzdCBmb3IgeWVhciBlZmZlY3QhIApUaGUgcnVuIHRpbWUgaXMgYWN0dWFsbHkgbm90IHRoYXQgYmFkIGZvciB0aGUgc2VhZ3Jhc3Nlcy4KVGhlIHNwZWNpZXMgc2luZ2xlZCBvdXQgYXMgc2lnbmlmaWNhbnQgYXJlIHByb2JhYmx5IHNvbWV3aGF0IGRpZmZlcmVudCAtIGhhdmUgdG8gY2hlY2shCgpSZWRvIHRoZSBiaXBsb3QsIGJlY2F1c2UgdGhpcyBvbmUgaXMgbm90IHZlcnkgcHJldHR5LiBJJ20gbm90IGFkZGluZyB0aGUgc3BlY2llcyBvbiB0b3AsIGZpcnN0IGJlY2F1c2UgSSdtIHRvbyBsYXp5IHRvIGZpZ3VyZSBvdXQgdGhlIHByb2NlZHVyZSBmb3Igb3JkZXJpbmcgdGhlbSwgYW5kIHNlY29uZCBiZWNhdXNlIHRoZSBwbG90IGdldHMgdG9vIGJ1c3kuICAgCmBgYHtyIGV4dHJhY3RfbHZtX2Nvb3JkX3pvc3RlcmF9CiMjIGV4dHJhY3QgdGhlIExWIGNvb3JkaW5hdGVzIG9mIHRoZSBzdGF0aW9ucyBmcm9tIHRoZSBtb2RlbCwgc28gdGhhdCB0aGUgcGxvdCBjYW4gYmUgcmVkb25lIGluIGdncGxvdCAKbHZzLmNvb3JkLnpvc3RlcmEgPC0gYXNfdGliYmxlKGx2bS56b3N0ZXJhJGx2Lm1lZGlhbikKCiMjIGFkZCB0aGUgc3RhdGlvbnMgZnJvbSB0aGUgb3JpZ2luYWwgem9vYmVudGhpYyB0YWJsZSAob3JkZXIgd2FzIG5vdCBtb2RpZmllZCkKKGx2cy5jb29yZC56b3N0ZXJhIDwtIGx2cy5jb29yZC56b3N0ZXJhICU+JSAKICBiaW5kX2NvbHMoem9vLmFibmQuem9zdGVyYSAlPiUgc2VsZWN0KHN0YXRpb24pKQopCgpgYGAKCk1ha2UgdGhlIHBsb3QgYW5kIHNhdmUgaXQuICAKYGBge3IgcGxvdF9sdm1fem9zdGVyYX0KKHBsb3QubHZtLnpvc3RlcmEgPC0gZ2dwbG90KGx2cy5jb29yZC56b3N0ZXJhKSArIAogICAgZ2VvbV9wb2ludChhZXMoeCA9IGx2MSwgeSA9IGx2MiwgY29sb3VyID0gc3RhdGlvbikpICsgCiAgICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJTZXQyIiwgbmFtZSA9ICJzdGF0aW9uIiwgCiAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gcGFzdGUwKCJaIiwgYXMubnVtZXJpYygodW5pcXVlKGx2cy5jb29yZC56b3N0ZXJhICU+JSBwdWxsKHN0YXRpb24pKSkpKSkgKwogICBsYWJzKHggPSAiTFYxIiwgeSA9ICJMVjIiKQopCgpgYGAKCldlbGwsIHRoaXMgaXMgYSB3ZWlyZCBvbmUgLSB0aGlzIHBsb3QgaXMgZmxpcHBlZCBhcm91bmQgMCBjb21wYXJlZCB0byB0aGUgb25lIHRoYXQgYm9yYWwncyBwbG90dGluZyBmdW5jdGlvbiBnaXZlcy4gT3RoZXJ3aXNlIG5vdGhpbmcgY2hhbmdlcyAtIHRoZSBzcGF0aWFsIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiBzYW1wbGVzIGFyZSBwcmVzZXJ2ZWQuIEkgc3VwcG9zZSBpdCBkb2Vzbid0IG1hdHRlciBtdWNoIC0gdGhlIGF4ZXMgYXJlIGFyYml0cmFyeSBhZnRlciBhbGwsIGJ1dCBzdHJhbmdlIHRoYXQgaXQgaGFwcGVucy4gIAoKYGBge3Igc2F2ZV9wbG90X2x2bV96b3N0ZXJhfQojIyBzYXZlIHRoZSBMVk0gcGxvdCBmb3IgdGhlIHNlYWdyYXNzCmdnc2F2ZShmaWxlID0gaGVyZShmaWd1cmVzLmRpciwgImx2bV96b3N0ZXJhLnBuZyIpLCAKICAgICAgIHBsb3QubHZtLnpvc3RlcmEsIAogICAgICAgd2lkdGggPSAxNSwgdW5pdHMgPSAiY20iLCBkcGkgPSAzMDApCmBgYAoKIyMjIyMgKipHTE0gZml0dGluZyBmb3IgYWJ1bmRhbmNlIC0gZW52aXJvbm1lbnRhbCBkYXRhKiogIApGaXQgR0xNcyB0byB0aGUgc2l0ZXMgeCBzcGVjaWVzIG1hdHJpeCB0byB0cnkgYW5kIGV4cGxhaW4gdGhlIG9ic2VydmVkIGRpZmZlcmVuY2VzIGluIGNvbW11bml0eSBzdHJ1Y3R1cmUgYnkgdGhlIHZhcmlhdGlvbiBvZiB0aGUgZW52aXJvbm1lbnRhbCBwYXJhbWV0ZXJzLiAgClRoZXNlIGZ1bmN0aW9ucyBhbGwgY29tZSBmcm9tIHBhY2thZ2UgKiptdmFidW5kKiouICAKSW1wb3J0IHRoZSBlbnZpcm9ubWVudGFsIGRhdGEgLSB0aGUgb25lIGNsZWFuZWQsIHByZXBhcmVkIGFuZCBzYXZlZCBpbiB0aGUgcHJldmlvdXMgbm90ZWJvb2sgKGNsYXNzaWNhbCBtdWx0aXZhcmlhdGUgbWV0aG9kcykuIEl0IGNvbnRhaW5zIGxvbmctdGVybSBhdmVyYWdlcyBmb3IgdGhlIHdhdGVyIGNvbHVtbiBkYXRhIChhcyBsb25nLXRlcm0gYXMgYXZhaWxhYmxlLCBhdCBsZWFzdCkgYXQgZWFjaCBzdGF0aW9uLCByZXBlYXRlZCBmb3IgZWFjaCByZXBsaWNhdGUsIHRoZSBzZWRpbWVudCBkYXRhICgyMDEzLTIwMTQpLCBhbmQgdGhlIHNlYWdyYXNzIGRhdGEgKDIwMTMtMjAxNCksIGFnYWluIHJlcGVhdGVkIHRvIHRoZSBzYW1lIG51bWJlciBvZiByZXBsaWNhdGVzLiBPbmx5IHRoZSB2YXJpYWJsZXMgZGV0ZXJtaW5lZCB0byBiZSBzaWduaWZpY2FudCBieSBQQ0EgYXJlIGtlcHQuICAgICAgIApgYGB7ciBpbXBvcnRfZW52X2RhdGFfem9zdGVyYX0gCmVudi56b3N0ZXJhIDwtIHJlYWRfY3N2KGhlcmUoc2F2ZS5kaXIsICJlbnZfZGF0YV9vcmRpbmF0aW9uc196b3N0ZXJhLmNzdiIpKQoKIyMgY29udmVydCBzdGF0aW9uIHRvIGZhY3RvcgooZW52Lnpvc3RlcmEgPC0gZW52Lnpvc3RlcmEgJT4lIAogICAgbXV0YXRlKHN0YXRpb24gPSBmYWN0b3Ioc3RhdGlvbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIlBvZGEiLCAiT3RtYW5saSIsICJWcm9tb3MiLCAiR3JhZGluYSIsICJSb3BvdGFtbyIpKSkKKQpgYGAKU3RhdGlvbiBpcyBhIGZhY3RvciwgdGhlIHJlc3Qgb2YgdGhlIHZhcmlhYmxlcyBhcmUgbnVtZXJpYy4gIAoKVHVybiB0aGUgem9vYmVudGhpYyBkYXRhIChtaW51cyB0aGUgYWxsLTAgdGF4YSkgaW50byBhIG1hdHJpeCAtIGVhc2llciBmb3IgdGhlIG12YWJ1bmQgcGFja2FnZSBhbmQgbWV0aG9kcyB0byBkZWFsIHdpdGguICAKYGBge3IgbWF0cml4X2FibmRfem9zdGVyYX0KIyMgdGhlcmUgaXMgYWxyZWFkeSBvbmUgc3Vic2V0IG9mIGZpbHRlcmVkIGNvdW50IGRhdGEgKDMyIHggOTQpIC0gdXNlIGl0IAp6b28ubXZhYm5kLnpvc3RlcmEgPC0gbXZhYnVuZCh6b28uYWJuZC5mbHQuem9zdGVyYSkKYGBgCgojIyMjIyMgKiptYW55R0xNIGJ5IExWTSBjbHVzdGVycyoqCkZpcnN0LCBsZXQncyBzZWUgaWYgdGhlIGdyb3VwcyBmcm9tIHRoZSBsYXRlbnQgdmFyaWFibGUgbW9kZWwgKG1vcmUgb3IgbGVzcyBlcXVhbCB0byB0aGUgY2x1c3RlcnMgZnJvbSB0aGUgY2xhc3NpY2FsIG9yZGluYXRpb24pIGFyZSB2YWxpZCwgYW5kIHdoaWNoIHNwZWNpZXMgZXhoaWJpdCBhIHJlc3BvbnNlLiAgCkknbSBnb2luZyB0byB0cnkgc29tZXRoaW5nIG5ldyBoZXJlIC0gMSkgbG9vc2UgY2x1c3RlcnMgZnJvbSB0aGUgTFZNIG9yZGluYXRpb24sIDEgPSBQb2RhLU90bWFubGksIDIgPSBWcm9tb3MsIDMgPSBHcmFkaW5hLVJvcG90YW1vLiAyKSBzdGF0aW9ucyBhcyBjbHVzdGVycywgYXMgSSBkaWQgYmVmb3JlIGZvciB0aGUgc2VhZ3Jhc3MgZGF0YSwgYWx0aG91Z2ggSSBkb24ndCBiZWxpZXZlIGl0J3MgdmFsaWQvanVzdGlmaWVkIHRvIGRvIHNvLi4uIDMpIGFub3RoZXIgY29uZmlndXJhdGlvbiBvZiBjbHVzdGVycyBmcm9tIHRoZSBMVk0gb3JkaW5hdGlvbjogMSA9IFoxLVoyLCAyID0gWjMsIDMgPSBaNCwgNCA9IFo1LiAgIApgYGB7ciBjbHVzdGVyc19sdm1fem9zdGVyYX0KIyMgY29uc3RydWN0IHRoZSB2ZWN0b3JzIG9mIHRoZSBjbHVzdGVycyBieSBoYW5kIC0gZmlyc3QsIHNpdHVhdGlvbiAxIGFib3ZlCmx2bS5jbHVzdGVycy56b3N0ZXJhLjEgPC0gcmVwKDE6MywgdGltZXMgPSBjKDE2LCA0LCAxMikpCihsdm0uY2x1c3RlcnMuem9zdGVyYS4xIDwtIGZhY3Rvcihsdm0uY2x1c3RlcnMuem9zdGVyYS4xKSkKCiMjIGFnYWluLCBmb3IgY2FzZSAyCmx2bS5jbHVzdGVycy56b3N0ZXJhLjIgPC0gcmVwKDE6NSwgdGltZXMgPSBjKDgsIDgsIDQsIDgsIDQpKQoobHZtLmNsdXN0ZXJzLnpvc3RlcmEuMiA8LSBmYWN0b3IobHZtLmNsdXN0ZXJzLnpvc3RlcmEuMikpCgojIyBhZ2FpbiwgZm9yIGNhc2UgMwpsdm0uY2x1c3RlcnMuem9zdGVyYS4zIDwtIHJlcCgxOjQsIHRpbWVzID0gYygxNiwgNCwgOCwgNCkpCihsdm0uY2x1c3RlcnMuem9zdGVyYS4zIDwtIGZhY3Rvcihsdm0uY2x1c3RlcnMuem9zdGVyYS4zKSkKYGBgCgoqKkxWTSBjbHVzdGVycyAtIGNhc2UgMSoqCkNoZWNrIHRoZSBtb2RlbCBhc3N1bXB0aW9ucy4gCjEuIE1lYW4tdmFyaWFuY2UgYXNzdW1wdGlvbiA9PiBkZXRlcm1pbmVzIHRoZSBjaG9pY2Ugb2YgZmFtaWx5IHBhcmFtZXRlci4gQ2FuIGJlIGNoZWNrZWQgYnkgcGxvdHRpbmcgcmVzaWR1YWxzIHZzIGZpdHM6IGlmIGxpdHRsZSBwYXR0ZXJuIC0gdGhlIGNob3NlbiBtZWFuLXZhcmlhbmNlIGFzc3VtcHRpb24gaXMgcGxhdXNpYmxlLiAgCkFub3RoZXIgd2F5OiBkaXJlY3QgcGxvdHRpbmcgKHZhcmlhbmNlIH4gbWVhbiksIGZvciBlYWNoIHNwZWNpZXMgd2l0aGluIGVhY2ggZmFjdG9yCmxldmVsLiAgCmBgYHtyIGNoZWNrX21lYW5fdmFyaWFuY2VfbHZtX3pvc3RlcmFfMX0KcGxvdChtYW55Z2xtKHpvby5tdmFibmQuem9zdGVyYSB+IGx2bS5jbHVzdGVycy56b3N0ZXJhLjEsIGZhbWlseSA9ICJuZWdhdGl2ZS5iaW5vbWlhbCIpKQoKbWVhbnZhci5wbG90KHpvby5tdmFibmQuem9zdGVyYSB+IGx2bS5jbHVzdGVycy56b3N0ZXJhLjEsIHRhYmxlID0gVFJVRSkKYGBgCgpJdCdzIG5vdCBwZXJmZWN0LCBidXQgaXQncyBub3QgdG9vIHRlcnJpYmxlIGVpdGhlci4gCgoyLiBBc3N1bWVkIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIG1lYW4gYWJ1bmRhbmNlIGFuZCBlbnZpcm9ubWVudGFsIHZhcmlhYmxlcyAtIGxpbmsgZnVuY3Rpb24gYW5kIGZvcm11bGEuCldoZW4gcXVhbnRpdGF0aXZlIHZhcmlhYmxlcyBhcmUgaW5jbHVkZWQgaW4gdGhlIG1vZGVsIChmb3Igbm93LCBub3QgcmVsZXZhbnQgLSB3aWxsIGJlIGluIHRoZSBuZXh0IG1vZGVsKSAtPiBpZiB0aGVyZSBpcyBhIHRyZW5kIGluIHNpemUgb2YgcmVzaWR1YWxzIGF0IGRpZmZlcmVudCBmaXR0ZWQgdmFsdWVzIChlLmcuIFUtc2hhcGUsLi4pID0gdmlvbGF0aW9uIG9mIHRoZSBsb2ctbGluZWFyaXR5IGFzc3VtcHRpb24uCiAgCkV2ZXJ5dGhpbmcgbG9va3MgbW9yZSBvciBsZXNzIGZpbmU7IGZpdCB0aGUgbW9kZWwuIApgYGB7ciBmaXRfZ2xtc19sdm1fem9zdGVyYV8xfQpnbG1zLmx2bS56b3N0ZXJhLjEgPC0gbWFueWdsbSh6b28ubXZhYm5kLnpvc3RlcmEgfiBsdm0uY2x1c3RlcnMuem9zdGVyYS4xLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFtaWx5ID0gIm5lZ2F0aXZlLmJpbm9taWFsIikKCmBgYAoKRXhwbG9yZSB0aGUgZml0IChyZXNpZHVhbHMsIGRpYWdub3N0aWMgcGxvdHMsIGV0Yy4pLiAgCmBgYHtyIGV4cGxvcmVfZ2xtc19sdm1fem9zdGVyYV8xfQojIyByZXNpZHVhbHMgdnMgZml0dGVkIHZhbHVlcwpwbG90KGdsbXMubHZtLnpvc3RlcmEuMSkKCiMjIGFsbCB0cmFkaXRpb25hbCAoZylsbSBkaWFnbm9zdGljIHBsb3RzCnBsb3QubWFueWdsbShnbG1zLmx2bS56b3N0ZXJhLjEsIHdoaWNoID0gMTozKQoKIyAjIyMgc291cmNlIG12YWJ1bmQgR0xNIHBsb3R0aW5nIGZ1bmN0aW9ucyBtb2RpZmllZCB0byB1c2UgYSBncmV5IHBhbGV0dGUgLSBJIGp1c3QgY2FuJ3QgcmVkbyB0aGVzZSBwbG90cyBvbiBteSBvd24sIHRoZSBmdW5jdGlvbiBpcyBkb2luZyB0b28gY29tcGxpY2F0ZWQgdGhpbmdzIGludGVybmFsbHkgdG8gc2NhbGUgdGhlIHggYW5kIHkgYXhlcwojIHNvdXJjZShoZXJlKGZ1bmN0aW9ucy5kaXIsICJkZWZhdWx0LnBsb3QubWFueWdsbV9ncmV5LlIiKSkKIyBzb3VyY2UoaGVyZShmdW5jdGlvbnMuZGlyLCAicGxvdC5tYW55Z2xtX2dyZXkuUiIpKQojIAojIHBhcihtZnJvdyA9IGMoMiwyKSkKIyBsYXBwbHkoMTozLCBmdW5jdGlvbihpKSBwbG90Lm1hbnlnbG0uZ3JleShnbG1zLmx2bS56b3N0ZXJhLCB3aGljaCA9IGksIHN1Yi5jYXB0aW9uID0gIiIpKQojIHBhcihtZnJvdyA9IGMoMSwgMSkpCgpgYGAKCkkgcmVhbGx5IGRvbid0IGxpa2UgdGhlIHJhaW5ib3cgcGFsZXR0ZSwgYnV0IEkgd291bGQgbGlrZSB0byBpbmNsdWRlIHRoZXNlIHBsb3RzIGluIG15IHRoZXNpcyByZXN1bHRzLi4gV2lsbCBoYXZlIHRvIGRvIHNvbWV0aGluZyBhYm91dCBpdCwganVzdCBub3QgcmlnaHQgbm93LiAgClNhdmUgdGhlIG1vZGVsISAgCmBgYHtyIHNhdmVfZ2xtc19sdm1fem9zdGVyYV8xfQp3cml0ZV9yZHMoZ2xtcy5sdm0uem9zdGVyYS4xLCAKICAgICAgICAgIGhlcmUoc2F2ZS5kaXIsICJnbG1zX2x2bV96b3N0ZXJhXzEuUkRTIikpCmBgYAoKCkxldCdzIHNlZSB0aGUgbW9kZWwgc3VtbWFyeSAoTkIgdGFrZXMgYSBMT1Qgb2YgdGltZSBpZiB0aGVyZSBhcmUgbWFueSByZXNhbXBsaW5ncyEpLiAgCmBgYHtyIHN1bW1hcnlfZ2xtc19sdm1fem9zdGVyYV8xfQooZ2xtcy5sdm0uem9zdGVyYS4xLnN1bW1hcnkgPC0gc3VtbWFyeShnbG1zLmx2bS56b3N0ZXJhLjEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVzdCA9ICJMUiIsIHAudW5pID0gImFkanVzdGVkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5Cb290ID0gOTk5LCAjIyBsaW1pdCB0aGUgbnVtYmVyIG9mIHBlcm11dGF0aW9ucyBpZiB5b3UganVzdCB3YW50IHRvIGNoZWNrIGl0IG91dAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hvdy50aW1lID0gImFsbCIpCikKYGBgCgpUaGUgZmFjdG9yIGlzIGhpZ2hseSBzaWduaWZpY2FudCBhY2NvcmRpbmcgdG8gdGhlIG1vZGVscy4gIApUaGlzIGFsc28gYWxsb3dzIHVzIHRvIHNlZSB3aGljaCBzcGVjaWVzIGV4aGliaXQgYSByZXNwb25zZSB0byB0aGUgY2hvc2VuIGZhY3Rvci4gClRoZSBMUiAobGlrZWxpaG9vZCByYXRpbykgc3RhdGlzdGljIGlzIHVzZWQgYXMgYSBtZWFzdXJlIG9mIHRoZSBzdHJlbmd0aCBvZiBpbmRpdmlkdWFsIHRheG9uIGNvbnRyaWJ1dGlvbnMgdG8gdGhlIG9ic2VydmVkIHBhdHRlcm5zLiAKSSdsbCBzYXZlIHRoZSBzdW1tYXJ5IGZvciBzYWZla2VlcGluZywgYnV0IEknbGwgYWxzbyBydW4gYW4gYW5vdmEgLSB0byBnZXQgYW4gYW5hbHlzaXMgb2YgZGV2aWFuY2UgdGFibGUgb24gdGhlIG1vZGVsIGZpdCAoYWxzbyBiZXR0ZXIgZm9yIGV4dHJhY3RpbmcgdGhlIHNwZWNpZXMgY29udHJpYnV0aW9ucywgb3IgYXQgbGVhc3QgSSBrbm93IGhvdyB0byBkbyBpdCkuICAKYGBge3Igc2F2ZV9zdW1tYXJ5X2dsbXNfbHZtX3pvc3RlcmFfMX0Kd3JpdGVfcmRzKGdsbXMubHZtLnpvc3RlcmEuMS5zdW1tYXJ5LCAKICAgICAgICAgIGhlcmUoc2F2ZS5kaXIsICJnbG1zX2x2bV96b3N0ZXJhXzFfc3VtbWFyeS5SRFMiKSkKYGBgCgpSdW4gdGhlIGFub3ZhIG9uIHRoZSBtb2RlbC4gCmBgYHtyIGFub3ZhX2dsbXNfbHZtX3pvc3RlcmFfMX0KKGdsbXMubHZtLnpvc3RlcmEuMS5hb3YgPC0gYW5vdmEubWFueWdsbShnbG1zLmx2bS56b3N0ZXJhLjEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZXN0ID0gIkxSIiwgcC51bmkgPSAiYWRqdXN0ZWQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbkJvb3QgPSA5OTksICMjIGxpbWl0IHRoZSBudW1iZXIgb2YgcGVybXV0YXRpb25zIGZvciBhIHNob3J0ZXIgcnVuIHRpbWUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFpcndpc2UuY29tcCA9IH5sdm0uY2x1c3RlcnMuem9zdGVyYS4xLCAjIyBjaGVjayB0aGUgcGFpcndpc2UgY29tcGFyaXNvbiBiZXR3ZWVuIGNsdXN0ZXJzCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNob3cudGltZSA9ICJhbGwiKSAKKQpgYGAKCkFhYWFuZCB0aGUgZGlmZmVyZW5jZXMgYmV0d2VlbiBjbHVzdGVycyBhcmUgaGlnaGx5IHNpZ25pZmljYW50IGluIHRoaXMgaXRlcmF0aW9uLi4gCgpTYXZlIHRoZSBBTk9WQSwgdG9vLiAgCmBgYHtyIHNhdmVfYW5vdmFfZ2xtc19sdm1fem9zdGVyYV8xfQp3cml0ZV9yZHMoZ2xtcy5sdm0uem9zdGVyYS4xLmFvdiwgCiAgICAgICAgICBoZXJlKHNhdmUuZGlyLCAiZ2xtc19sdm1fem9zdGVyYV8xX2Fub3ZhLlJEUyIpKQpgYGAKCk5PVyBsZXQncyBnZXQgdGhlIHRheGEgd2l0aCB0aGUgaGlnaGVzdCBjb250cmlidXRpb25zIHRvIHRoZSB0ZXN0ZWQgcGF0dGVybi4gIApgYGB7ciByZWxhdGl2ZV90YXhvbl9jb250cmliX2dsbXNfbHZtX3pvc3RlcmFfMX0KIyMgZ2V0IHRoZSB0b3AgY29udHJpYnV0aW5nIHNwZWNpZXMgZm9yIHRoZSBpbml0aWFsIHpvc3RlcmEgR0xNcyAKKHRvcC5zcC5nbG1zLmx2bS56b3N0ZXJhLjEgPC0gdG9wX25fc3BfZ2xtKGdsbXMubHZtLnpvc3RlcmEuMS5hb3YsIHRvdC5kZXYuZXhwbCA9IDAuNzUpCikKCiMjIHVuZm9ydHVuYXRlbHksIG12YWJ1bmQgbGlrZXMgdG8gcmVuYW1lIG15IHNwZWNpZXMgd2hlbiBjb252ZXJ0aW5nIHRoZSBkYXRhIHRvIG1hdHJpeCAobm8gc3BhY2VzIGluIG5hbWVzKSwgYW5kIHNpbmNlIEknbSBnb2luZyB0byBsb29rIHRoZW0gdXAgaW4gbXkgaW5pdGlhbCB1bnRyYW5zZm9ybWVkIGNvdW50IGRhdGEsIEkgaGF2ZSB0byBjaGFuZ2UgdGhlbSBiYWNrLi4gICAKbmFtZXModG9wLnNwLmdsbXMubHZtLnpvc3RlcmEuMSkgPC0gbmFtZXModG9wLnNwLmdsbXMubHZtLnpvc3RlcmEuMSkgJT4lIAogIHN0cl9yZXBsYWNlKHBhdHRlcm4gPSAiXFwuIiwgcmVwbGFjZW1lbnQgPSAiICIpCgp0b3Auc3AuZ2xtcy5sdm0uem9zdGVyYS4xCmBgYAoKVHJ5IHRvIHBsb3QgdGhlc2UgdG9wIGNvbnRyaWJ1dGluZyBzcGVjaWVzIC0gZm9yIHdoYXRldmVyIHRoYXQncyB3b3J0aCwgYmVjYXVzZSA1MCBzcGVjaWVzIG9uIGEgcGxvdCBpcyBzdGlsbCBhIG1vbnN0cm9zaXR5LiAgCgpgYGB7ciBwbG90X3JlbGF0aXZlX3RheG9uX2NvbnRyaWJfZ2xtc19sdm1fem9zdGVyYV8xfQojIyBnZXQgdGhlIHNwZWNpZXMgYW5kIHRoZWlyIGFidW5kYW5jZXMgZnJvbSB0aGUgb3JpZ2luYWwgY291bnQgZGF0YSwgYW5kIHRyYW5zZm9ybSB0aGVtIHRvIGxvbmcgZm9ybWF0CihhYm5kLnRvcC5zcC5nbG1zLmx2bS56b3N0ZXJhLjEgPC0gem9vLmFibmQuem9zdGVyYSAlPiUgCiAgIHNlbGVjdChzdGF0aW9uLCBuYW1lcyh0b3Auc3AuZ2xtcy5sdm0uem9zdGVyYS4xKSkgJT4lIAogICBnYXRoZXIoa2V5ID0gInNwZWNpZXMiLCB2YWx1ZSA9ICJjb3VudCIsIC1zdGF0aW9uKSAlPiUgCiAgICMjIHR1cm4gc3BlY2llcyBpbnRvIGEgZmFjdG9yLCBvciB5b3UnbGwgYmUgdmVyeSB2ZXJ5IHNvcnJ5IGxhdGVyLCB3aGVuIHRoZXkncmUgb3V0IG9mIG9yZGVyIG9uIHRoZSBwbG90LiBOQiBuZWVkIHRvIGJlIGluIFJFVkVSU0Ugb3JkZXIsIGJlY2F1c2UgZ2dwbG90IHBsb3RzIGZyb20gYm90dG9tIHRvIHRvcCwgYW5kIEkgd2FudCB0aGUgdG9wLWNvbnRyaWJ1dGluZyBzcGVjaWVzIG9uIHRvcC4gCiAgIG11dGF0ZShzcGVjaWVzID0gZmFjdG9yKHNwZWNpZXMsIGxldmVscyA9IHJldihuYW1lcyh0b3Auc3AuZ2xtcy5sdm0uem9zdGVyYS4xKSkpKSAlPiUgCiAgIG11dGF0ZShncm91cCA9IGZhY3RvcihjYXNlX3doZW4oc3RhdGlvbiAlaW4lIGMoIlBvZGEiLCAiT3RtYW5saSIpIH4gMSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdGlvbiA9PSAiVnJvbW9zIiB+IDIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXRpb24gJWluJSBjKCJHcmFkaW5hIiwgIlJvcG90YW1vIikgfiAzKSkpICMjIGFkZCB0aGUgZ3JvdXBzIHRvIHRoZSBsb25nIGRmIAopCgoKKHBsb3QudG9wLnNwLmdsbXMubHZtLnpvc3RlcmEuMSA8LSBwbG90X3RvcF9uKGFibmQudG9wLnNwLmdsbXMubHZtLnpvc3RlcmEuMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBzcGVjaWVzLCB5ID0gbG9nX3lfbWluKGNvdW50KSwgY29sb3VyID0gZ3JvdXApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYnMubGVnZW5kID0gcGFzdGUwKCJncm91cCIsIGFzLmNoYXJhY3RlcihsZXZlbHMoYWJuZC50b3Auc3AuZ2xtcy5sdm0uem9zdGVyYS4xJGdyb3VwKSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYi55ID0gIkFidW5kYW5jZSAobG9nKHkvbWluICsgMSkpIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYWxldHRlID0gIlNldDIiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLCBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCgopCmBgYAoKV2VsbCB0aGlzIGlzIGEgbmlnaHRtYXJpc2ggcGxvdCwgYnV0IG1vcmUgdG9sZXJhYmxlIHRoYW4gdGhlIG9uZSBmb3IgdGhlIHNhbmQgc3RhdGlvbnMgLSB0aGVyZSBhcmUgbGVzcyBzcGVjaWVzIGhlcmUsIHNvIGF0IGxlYXN0IGl0J3MgcmVhZGFibGUuLiAgIAoKRXh0cmFjdCB0aGUgdG9wLWNvbnRyaWJ1dGluZyBzcGVjaWVzIHRvIGVhY2ggY2x1c3RlciAodGhpcyBzYW1lIG5pZ2h0bWFyZSBhYm92ZSwgYnV0IGFzIGEgdGFibGUpLiBUaGlzIGNodW5rIGlzIFNUSUxMIGhvcGVsZXNzbHkgdWdseSBhbmQgY2x1bXN5LiAgCmBgYHtyIHRhYmxlX3JlbGF0aXZlX3RheG9uX2NvbnRyaWJfZ2xtc19sdm1fem9zdGVyYV8xfQp0b3Auc3AuYWJuZC5nbG1zLmx2bS56b3N0ZXJhLjEgPC0gbGFwcGx5KG5hbWVzKGdsbXMubHZtLnpvc3RlcmEuMS5zdW1tYXJ5JGFsaWFzZWQpLCBmdW5jdGlvbih4KSB0b3Bfc3BfZ2xtc190YWJsZShnbG1zLmx2bS56b3N0ZXJhLjEuc3VtbWFyeSwgeCwgcCA9IDAuMDUpKSAKCiMjIGZpeCBzcGVjaWVzIG5hbWVzIChyZW1vdmUgZG90KSAKdG9wLnNwLmFibmQuZ2xtcy5sdm0uem9zdGVyYS4xIDwtIGxhcHBseSh0b3Auc3AuYWJuZC5nbG1zLmx2bS56b3N0ZXJhLjEsIGZ1bmN0aW9uKHgpIHggJT4lIG11dGF0ZShzcGVjaWVzID0gc3RyX3JlcGxhY2Uoc3BlY2llcywgcGF0dGVybiA9ICJcXC4iLCByZXBsYWNlbWVudCA9ICIgIikpKQoKIyMgcmVuYW1lIGNvbHVtbnMgKD0gZ3JvdXAgbmFtZXMpIC0gcmlnaHQgbm93IHRoZXkgYXJlIHNvbWV0aGluZyBsaWtlICJsdm0uY2x1c3RlcnMuem9zdGVyYTIiIGV0Yy4KdG9wLnNwLmFibmQuZ2xtcy5sdm0uem9zdGVyYS4xIDwtIGxhcHBseSh0b3Auc3AuYWJuZC5nbG1zLmx2bS56b3N0ZXJhLjEsIGZ1bmN0aW9uKHgpIHggJT4lIHJlbmFtZV9hdCh2YXJzKGNvbnRhaW5zKCJsdm0uY2x1c3RlcnMuem9zdGVyYS4xIikpLCBsaXN0KH5zdHJfcmVwbGFjZV9hbGwoLiwgcGF0dGVybiA9ICJsdm0uY2x1c3RlcnMuem9zdGVyYS4xIiwgImdyb3VwXyIpKSkpCgp0b3Auc3AuYWJuZC5nbG1zLmx2bS56b3N0ZXJhLjEgPC0gbGFwcGx5KHRvcC5zcC5hYm5kLmdsbXMubHZtLnpvc3RlcmEuMSwgZnVuY3Rpb24oeCkgeCAlPiUgcmVuYW1lX2F0KHZhcnMoY29udGFpbnMoIkludGVyY2VwdCIpKSwgbGlzdCh+c3RyX3JlcGxhY2VfYWxsKC4sIHBhdHRlcm4gPSAiXFwoSW50ZXJjZXB0XFwpIiwgImdyb3VwXzEiKSkpKQoKCiMjIHB1bGwgdGhlIGFidW5kYW5jZXMgZnJvbSB0aGUgb3JpZ2luYWwgY291bnQgZGYgYW5kIGFkZCB0byB0aGUgc3VtbWFyeSBnbG0gdGFibGVzIAojIyBtYWtlIGEgbG9uZyBkZiBvZiBhYnVuZGFuY2VzICYgYWRkIGNsdXN0ZXJzICAKem9vLmFibmQuem9zdGVyYS5sb25nLjEgPC0gem9vLmFibmQuem9zdGVyYSAlPiUKICBzZWxlY3QoLWMobW9udGg6cmVwbGljYXRlKSkgJT4lCiAgZ2F0aGVyKGtleSA9ICJzcGVjaWVzIiwgdmFsdWUgPSAiY291bnQiLCAtc3RhdGlvbikgJT4lIAogIG11dGF0ZShncm91cCA9IGNhc2Vfd2hlbihzdGF0aW9uICVpbiUgYygiUG9kYSIsICJPdG1hbmxpIikgfiAxLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdGlvbiA9PSAiVnJvbW9zIiB+IDIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0aW9uICVpbiUgYygiR3JhZGluYSIsICJSb3BvdGFtbyIpIH4gMykKICAgICAgICAgKQoKIyMgc3VtIHNwIGFidW5kYW5jZXMgYnkgZ3JvdXA7IG5lc3QgYnkgZ3JvdXAKem9vLmFibmQuem9zdGVyYS5sb25nLjEuc21yeSA8LSB6b28uYWJuZC56b3N0ZXJhLmxvbmcuMSAlPiUgCiAgZ3JvdXBfYnkoc3BlY2llcywgZ3JvdXApICU+JSAKICBzdW1tYXJpc2UodG90YWxfY291bnQgPSBzdW0oY291bnQpKSAlPiUgCiAgZ3JvdXBfYnkoZ3JvdXApICU+JQogIG5lc3QoKQoKIyMgYWRkIHRoZSBjb3VudHMgdG8gdGhlIGdyb3VwIGRmcyAtIHdvdyB0aGF0J3MgYW4gdWdseSwgdWdseSBoYWNrLiBXaXNoIEkgaGFkIG1vcmUgdGltZSB0byB3cml0ZSB0aGlzIHVwIHByb3Blcmx5Li4gCnRvcC5zcC5hYm5kLmdsbXMubHZtLnpvc3RlcmEuMSA8LSBtYXAyKHRvcC5zcC5hYm5kLmdsbXMubHZtLnpvc3RlcmEuMSwgem9vLmFibmQuem9zdGVyYS5sb25nLjEuc21yeSAlPiUgcHVsbChncm91cCksIH5sZWZ0X2pvaW4oLngsIHpvby5hYm5kLnpvc3RlcmEubG9uZy4xLnNtcnkgJT4lIGZpbHRlcihncm91cCA9PSAueSkgJT4lIHVubmVzdCgpLCBieSA9ICJzcGVjaWVzIikpCgojIyBzaW5jZSB0aGVzZSBhcmUgc3VtIGNvdW50cyBvdmVyIGFsbCB0aGUgcmVwbGljYXRlcyAodGhhdCdzIHdoeSB0aGUgbW9uc3Ryb3VzIG51bWJlcnMpLCBhdmVyYWdlIHRoZW0gdG8gYmUgbWVhbiBjb3VudHMgcGVyIGdyb3VwLiBOQiBkaWZmZXJlbnQgZ3JvdXBzIGNvbnNpc3Qgb2YgZGlmZmVyZW50IG51bWJlcnMgb2YgcmVwbGljYXRlcywgYi5jLiBzb21lIGdyb3VwcyBjb25zaXN0IG9mIG1vcmUgdGhhbiBvbmUgc3RhdGlvbgoodG9wLnNwLmFibmQuZ2xtcy5sdm0uem9zdGVyYS4xIDwtIG1hcDIodG9wLnNwLmFibmQuZ2xtcy5sdm0uem9zdGVyYS4xLCBjKDE2LCA0LCAxMiksIGZ1bmN0aW9uKHgsIHkpIHggJT4lIG11dGF0ZShtZWFuX2NvdW50ID0gdG90YWxfY291bnQveSkpCikKYGBgCgpJbiB0aGlzIGNhc2UsIHRoZSBtb2RlbCBzaG93cyB3aGljaCBzcGVjaWVzIGV4aGliaXQgYSByZWFjdGlvbiBiYXNlZCBvbiB0aGUgY2hvc2VuIGdyb3VwcyAtIGluIG90aGVyIHdvcmRzLCB3aGljaCBzcGVjaWVzIGFyZSBtb3JlIGxpa2VseSB0byBiZSBtb3JlL2xlc3MgYWJ1bmRhbnQgaW4gZWFjaCBncm91cC4gIApJIGhhdmUgdG8gc2F5LCBpbiB0aGUgY2FzZSBvZiB0aGUgc2VhZ3Jhc3NlcyBhbmQgY2FzZSAxIGNsdXN0ZXJzLCB0aGVyZSBhcmUgbXVjaCBmZXdlciBzcGVjaWVzIHRoYXQgZXhoaWJpdCBhIHNpZ25pZmljYW50IHJlc3BvbnNlIC0gYXJvdW5kIDEwIGZvciBlYWNoIGdyb3VwLiAgICAgClRoZSBMUnMgYXJlIGxvd2VyIGZvciBncm91cHMgMiBhbmQgMyAtIG5vdCBzdXJlIGlmIHRoaXMgbWVhbnMgYW55dGhpbmcsIGJ1dCBmb3IgZ3JvdXAgMSB0aGV5IGFyZSBtdWNoIG11Y2ggaGlnaGVyLi4gICAKRm9yICoqZ3JvdXAgMSoqICg9IFoxLVoyKSwgdGhlIHNwZWNpZXMvdGF4YSB3aXRoIHNpZ25pZmljYW50bHkgKipoaWdoZXIgYWJ1bmRhbmNlKiogYXJlOiBCaXR0aXVtIHJldGljdWxhdHVtLCBDYXBpdGVsbGEgbWluaW1hLCBPbGlnb2NoYWV0YSwgSC4gZmlsaWZvcm1pcywgUG9seWRvcmEgY2lsaWF0YSwgUHJpb25vc3BpbyBjaXJyaWZlcmEsIFIuIG1lbWJyYW5hY2VhLCBBLiBhbGJhLCBBLmRpYWRlbWEsIE0uIGFjaGVydXNpY3VtOyBhbmQgdGhlIG9ubHkgb25lIHdpdGggYSBzaWduaWZpY2FudGx5ICoqbG93ZXIgYWJ1bmRhbmNlKiogLSBDaGFtZWxlYSBnYWxsaW5hLiAgIApGb3IgKipncm91cCAyKiogKD0gWjMpLCB0aGUgc3BlY2llcyB3aXRoICoqaGlnaGVyIGFidW5kYW5jZSoqIGFyZTogTS4gYWNoZXJ1c2ljdW0sIFMuIGZpbGljb3JuaXMsIEEuZGFkZW1hLiBUaGUgc3BlY2llcyB3aXRoICoqbG93ZXIgYWJ1bmRhbmNlKiogYXJlOiBCLiByZXRpY3VsYXR1bSwgQS4gYWxiYSwgT2xpZ29jaGFldGEsIFMuIGNsYXZhdGEsIFAuIGNpbGlhdGEsIFAuIGNpcnJpZmVyYSwgSC4gZmlsaWZvcm1pcy4gIApGb3IgKipncm91cCAzKiogKD0gWjQtWjUpLCB0aGUgc3BlY2llcyB3aXRoICoqaGlnaGVyIGFidW5kYW5jZSoqIGFyZTogQ3VtZWxsYSBsaW1pY29sYSwgQXBzZXVkb3BzaXMgb3N0cm91bW92aSwgQ2FwaXRlbGxhIGNhcGl0YXRhLCBNeXRpbGFzdGVyIGxpbmVhdHVzLCBMb3JpcGVzIG9yYmljdWxhdHVzOyBsZXNzIHNvLCBidXQgc3RpbGwgcHJlc2VudCAtIEMuIGdhbGxpbmEsIFMuIGNsYXZhdGEuIFRoZSBzcGVjaWVzIHdpdGggKipsb3dlciBhYnVuZGFuY2UqKiBhcmU6IEFicmEgYWxiYSwgTWVsaW5uYSBwYWxtYXRhICh0b3RhbGx5IGFic2VudCkuICAKCgpJJ2xsIHRlc3QgZWFjaCBzdGF0aW9uIGFzIGl0cyBvd24gZ3JvdXAsIHRvbyAoYXMgSSBkaWQgYmVmb3JlLCB3aXRoIHRoZSBjbGFzc2ljYWwgbXVsdGl2YXJpYXRlIG1ldGhvZHMpIC0gSSdtIG5vdCBzdXJlIGhvdyBtdWNoIEkgY2FuIHRydXN0IHRoaXMgZ3JvdXBpbmcgKGluIHBhcnRpY3VsYXIgZ3JvdXAgMyBpcyBhIGJpdCBmYXItZmV0Y2hlZCwgaWYgeW91IGFzayBtZS4uKS4gIAoKCioqTFZNIGNsdXN0ZXJzIC0gY2FzZSAyKioKQ2hlY2sgdGhlIG1vZGVsIGFzc3VtcHRpb25zLiAgCmBgYHtyIGNoZWNrX21lYW5fdmFyaWFuY2VfbHZtX3pvc3RlcmFfMn0KcGxvdChtYW55Z2xtKHpvby5tdmFibmQuem9zdGVyYSB+IGx2bS5jbHVzdGVycy56b3N0ZXJhLjIsIGZhbWlseSA9ICJuZWdhdGl2ZS5iaW5vbWlhbCIpKQoKbWVhbnZhci5wbG90KHpvby5tdmFibmQuem9zdGVyYSB+IGx2bS5jbHVzdGVycy56b3N0ZXJhLjIsIHRhYmxlID0gVFJVRSkKYGBgCgpJdCdzIG5vdCBwZXJmZWN0LCBidXQgaXQncyBub3QgdG9vIHRlcnJpYmxlIGVpdGhlci4gSSB0aGluayBpdCdzIGEgbGl0dGxlIHdvcnNlIHRoYW4gdGhlIGNhc2UgMSBmaXQuICAKCjIuIEFzc3VtZWQgcmVsYXRpb25zaGlwIGJldHdlZW4gbWVhbiBhYnVuZGFuY2UgYW5kIGVudmlyb25tZW50YWwgdmFyaWFibGVzIC0gbGluayBmdW5jdGlvbiBhbmQgZm9ybXVsYS4KCkV2ZXJ5dGhpbmcgbG9va3MgbW9yZSBvciBsZXNzIGZpbmU7IGZpdCB0aGUgbW9kZWwuIApgYGB7ciBmaXRfZ2xtc19sdm1fem9zdGVyYV8yfQpnbG1zLmx2bS56b3N0ZXJhLjIgPC0gbWFueWdsbSh6b28ubXZhYm5kLnpvc3RlcmEgfiBsdm0uY2x1c3RlcnMuem9zdGVyYS4yLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFtaWx5ID0gIm5lZ2F0aXZlLmJpbm9taWFsIikKCmBgYAoKRXhwbG9yZSB0aGUgZml0IChyZXNpZHVhbHMsIGRpYWdub3N0aWMgcGxvdHMsIGV0Yy4pLiAgCmBgYHtyIGV4cGxvcmVfZ2xtc19sdm1fem9zdGVyYV8yfQojIyByZXNpZHVhbHMgdnMgZml0dGVkIHZhbHVlcwpwbG90KGdsbXMubHZtLnpvc3RlcmEuMikKCiMjIGFsbCB0cmFkaXRpb25hbCAoZylsbSBkaWFnbm9zdGljIHBsb3RzCnBsb3QubWFueWdsbShnbG1zLmx2bS56b3N0ZXJhLjIsIHdoaWNoID0gMTozKQoKIyAjIyMgc291cmNlIG12YWJ1bmQgR0xNIHBsb3R0aW5nIGZ1bmN0aW9ucyBtb2RpZmllZCB0byB1c2UgYSBncmV5IHBhbGV0dGUgLSBJIGp1c3QgY2FuJ3QgcmVkbyB0aGVzZSBwbG90cyBvbiBteSBvd24sIHRoZSBmdW5jdGlvbiBpcyBkb2luZyB0b28gY29tcGxpY2F0ZWQgdGhpbmdzIGludGVybmFsbHkgdG8gc2NhbGUgdGhlIHggYW5kIHkgYXhlcwojIHNvdXJjZShoZXJlKGZ1bmN0aW9ucy5kaXIsICJkZWZhdWx0LnBsb3QubWFueWdsbV9ncmV5LlIiKSkKIyBzb3VyY2UoaGVyZShmdW5jdGlvbnMuZGlyLCAicGxvdC5tYW55Z2xtX2dyZXkuUiIpKQojIAojIHBhcihtZnJvdyA9IGMoMiwyKSkKIyBsYXBwbHkoMjozLCBmdW5jdGlvbihpKSBwbG90Lm1hbnlnbG0uZ3JleShnbG1zLmx2bS56b3N0ZXJhLCB3aGljaCA9IGksIHN1Yi5jYXB0aW9uID0gIiIpKQojIHBhcihtZnJvdyA9IGMoMiwgMikpCgpgYGAKClNhdmUgdGhlIG1vZGVsISAgCmBgYHtyIHNhdmVfZ2xtc19sdm1fem9zdGVyYV8yfQp3cml0ZV9yZHMoZ2xtcy5sdm0uem9zdGVyYS4yLCAKICAgICAgICAgIGhlcmUoc2F2ZS5kaXIsICJnbG1zX2x2bV96b3N0ZXJhXzIuUkRTIikpCmBgYAoKCkxldCdzIHNlZSB0aGUgbW9kZWwgc3VtbWFyeSAoTkIgdGFrZXMgYSBMT1Qgb2YgdGltZSBpZiB0aGVyZSBhcmUgbWFueSByZXNhbXBsaW5ncyEpLiAgCmBgYHtyIHN1bW1hcnlfZ2xtc19sdm1fem9zdGVyYV8yfQooZ2xtcy5sdm0uem9zdGVyYS4yLnN1bW1hcnkgPC0gc3VtbWFyeShnbG1zLmx2bS56b3N0ZXJhLjIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZXN0ID0gIkxSIiwgcC51bmkgPSAiYWRqdXN0ZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuQm9vdCA9IDk5OSwgIyMgbGltaXQgdGhlIG51bWJlciBvZiBwZXJtdXRhdGlvbnMgaWYgeW91IGp1c3Qgd2FudCB0byBjaGVjayBpdCBvdXQKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hvdy50aW1lID0gImFsbCIpCikKYGBgCgpUaGUgZmFjdG9yIGlzIGhpZ2hseSBzaWduaWZpY2FudCBhY2NvcmRpbmcgdG8gdGhlIG1vZGVscy4gIAogCkFnYWluLCBzYXZlIHRoZSBzdW1tYXJ5IGZvciBzYWZla2VlcGluZywgYnV0IGFsc28gcnVuIGFuIGFub3ZhLiAgCmBgYHtyIHNhdmVfc3VtbWFyeV9nbG1zX2x2bV96b3N0ZXJhXzJ9CndyaXRlX3JkcyhnbG1zLmx2bS56b3N0ZXJhLjIuc3VtbWFyeSwgCiAgICAgICAgICBoZXJlKHNhdmUuZGlyLCAiZ2xtc19sdm1fem9zdGVyYV8yX3N1bW1hcnkuUkRTIikpCmBgYAoKUnVuIHRoZSBhbm92YSBvbiB0aGUgbW9kZWwuIApgYGB7ciBhbm92YV9nbG1zX2x2bV96b3N0ZXJhXzJ9CihnbG1zLmx2bS56b3N0ZXJhLjIuYW92IDwtIGFub3ZhLm1hbnlnbG0oZ2xtcy5sdm0uem9zdGVyYS4yLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZXN0ID0gIkxSIiwgcC51bmkgPSAiYWRqdXN0ZWQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuQm9vdCA9IDk5OSwgIyMgbGltaXQgdGhlIG51bWJlciBvZiBwZXJtdXRhdGlvbnMgZm9yIGEgc2hvcnRlciBydW4gdGltZSAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhaXJ3aXNlLmNvbXAgPSB+bHZtLmNsdXN0ZXJzLnpvc3RlcmEuMiwgIyMgY2hlY2sgdGhlIHBhaXJ3aXNlIGNvbXBhcmlzb24gYmV0d2VlbiBjbHVzdGVycwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNob3cudGltZSA9ICJhbGwiKSAKKQpgYGAKCkFnYWluLCB0aGVzZSBncm91cHMgYXJlIHN1ZmZpY2llbnRseSBkaWZmZXJlbnQgZnJvbSBvbmUgYW5vdGhlci4uIE5vIGNsdWUgaGVyZS4gCgpTYXZlIHRoZSBBTk9WQSwgdG9vLiAgCmBgYHtyIHNhdmVfYW5vdmFfZ2xtc19sdm1fem9zdGVyYV8yfQp3cml0ZV9yZHMoZ2xtcy5sdm0uem9zdGVyYS4yLmFvdiwgCiAgICAgICAgICBoZXJlKHNhdmUuZGlyLCAiZ2xtc19sdm1fem9zdGVyYV8yX2Fub3ZhLlJEUyIpKQpgYGAKCk5PVyBsZXQncyBnZXQgdGhlIHRheGEgd2l0aCB0aGUgaGlnaGVzdCBjb250cmlidXRpb25zIHRvIHRoZSB0ZXN0ZWQgcGF0dGVybi4gIApgYGB7ciByZWxhdGl2ZV90YXhvbl9jb250cmliX2dsbXNfbHZtX3pvc3RlcmFfMn0KIyMgZ2V0IHRoZSB0b3AgY29udHJpYnV0aW5nIHNwZWNpZXMgZm9yIHRoZSBpbml0aWFsIHpvc3RlcmEgR0xNcyAKKHRvcC5zcC5nbG1zLmx2bS56b3N0ZXJhLjIgPC0gdG9wX25fc3BfZ2xtKGdsbXMubHZtLnpvc3RlcmEuMi5hb3YsIHRvdC5kZXYuZXhwbCA9IDAuNzUpCikKCiMjIHVuZm9ydHVuYXRlbHksIG12YWJ1bmQgbGlrZXMgdG8gcmVuYW1lIG15IHNwZWNpZXMgd2hlbiBjb252ZXJ0aW5nIHRoZSBkYXRhIHRvIG1hdHJpeCAobm8gc3BhY2VzIGluIG5hbWVzKSwgYW5kIHNpbmNlIEknbSBnb2luZyB0byBsb29rIHRoZW0gdXAgaW4gbXkgaW5pdGlhbCB1bnRyYW5zZm9ybWVkIGNvdW50IGRhdGEsIEkgaGF2ZSB0byBjaGFuZ2UgdGhlbSBiYWNrLi4gICAKbmFtZXModG9wLnNwLmdsbXMubHZtLnpvc3RlcmEuMikgPC0gbmFtZXModG9wLnNwLmdsbXMubHZtLnpvc3RlcmEuMikgJT4lIAogIHN0cl9yZXBsYWNlKHBhdHRlcm4gPSAiXFwuIiwgcmVwbGFjZW1lbnQgPSAiICIpCgp0b3Auc3AuZ2xtcy5sdm0uem9zdGVyYS4yCmBgYAoKVHJ5IHRvIHBsb3QgdGhlc2UgdG9wIGNvbnRyaWJ1dGluZyBzcGVjaWVzIC0gZm9yIHdoYXRldmVyIHRoYXQncyB3b3J0aCwgYmVjYXVzZSA1MCBzcGVjaWVzIG9uIGEgcGxvdCBpcyBzdGlsbCBhIG1vbnN0cm9zaXR5LiAgCgpgYGB7ciBwbG90X3JlbGF0aXZlX3RheG9uX2NvbnRyaWJfZ2xtc19sdm1fem9zdGVyYV8yfQojIyBnZXQgdGhlIHNwZWNpZXMgYW5kIHRoZWlyIGFidW5kYW5jZXMgZnJvbSB0aGUgb3JpZ2luYWwgY291bnQgZGF0YSwgYW5kIHRyYW5zZm9ybSB0aGVtIHRvIGxvbmcgZm9ybWF0CihhYm5kLnRvcC5zcC5nbG1zLmx2bS56b3N0ZXJhLjIgPC0gem9vLmFibmQuem9zdGVyYSAlPiUgCiAgIHNlbGVjdChzdGF0aW9uLCBuYW1lcyh0b3Auc3AuZ2xtcy5sdm0uem9zdGVyYS4yKSkgJT4lIAogICBnYXRoZXIoa2V5ID0gInNwZWNpZXMiLCB2YWx1ZSA9ICJjb3VudCIsIC1zdGF0aW9uKSAlPiUgCiAgICMjIHR1cm4gc3BlY2llcyBpbnRvIGEgZmFjdG9yLCBvciB5b3UnbGwgYmUgdmVyeSB2ZXJ5IHNvcnJ5IGxhdGVyLCB3aGVuIHRoZXkncmUgb3V0IG9mIG9yZGVyIG9uIHRoZSBwbG90LiBOQiBuZWVkIHRvIGJlIGluIFJFVkVSU0Ugb3JkZXIsIGJlY2F1c2UgZ2dwbG90IHBsb3RzIGZyb20gYm90dG9tIHRvIHRvcCwgYW5kIEkgd2FudCB0aGUgdG9wLWNvbnRyaWJ1dGluZyBzcGVjaWVzIG9uIHRvcC4gCiAgIG11dGF0ZShzcGVjaWVzID0gZmFjdG9yKHNwZWNpZXMsIGxldmVscyA9IHJldihuYW1lcyh0b3Auc3AuZ2xtcy5sdm0uem9zdGVyYS4yKSkpKSAlPiUgCiAgIG11dGF0ZShncm91cCA9IGZhY3RvcihjYXNlX3doZW4oc3RhdGlvbiA9PSAiUG9kYSIgfiAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXRpb24gPT0gIk90bWFubGkiIH4gMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0aW9uID09ICJWcm9tb3MiIH4gMywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdGlvbiA9PSAiR3JhZGluYSIgfiA0LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0aW9uID09ICJSb3BvdGFtbyIgfiA1KSkpCikKCgoocGxvdC50b3Auc3AuZ2xtcy5sdm0uem9zdGVyYS4yIDwtIHBsb3RfdG9wX24oYWJuZC50b3Auc3AuZ2xtcy5sdm0uem9zdGVyYS4yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0gc3BlY2llcywgeSA9IGxvZ195X21pbihjb3VudCksIGNvbG91ciA9IGdyb3VwKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYnMubGVnZW5kID0gcGFzdGUwKCJncm91cCIsIGFzLmNoYXJhY3RlcihsZXZlbHMoYWJuZC50b3Auc3AuZ2xtcy5sdm0uem9zdGVyYS4yJGdyb3VwKSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiLnkgPSAiQWJ1bmRhbmNlIChsb2coeS9taW4gKyAxKSkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFsZXR0ZSA9ICJTZXQyIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIiwgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQoKKQpgYGAKCgpFeHRyYWN0IHRoZSB0b3AtY29udHJpYnV0aW5nIHNwZWNpZXMgdG8gZWFjaCBjbHVzdGVyICh0aGlzIHNhbWUgbmlnaHRtYXJlIGFib3ZlLCBidXQgYXMgYSB0YWJsZSkuIFRoaXMgY2h1bmsgaXMgU1RJTEwgaG9wZWxlc3NseSB1Z2x5IGFuZCBjbHVtc3kuICAKYGBge3IgdGFibGVfcmVsYXRpdmVfdGF4b25fY29udHJpYl9nbG1zX2x2bV96b3N0ZXJhXzJ9CnRvcC5zcC5hYm5kLmdsbXMubHZtLnpvc3RlcmEuMiA8LSBsYXBwbHkobmFtZXMoZ2xtcy5sdm0uem9zdGVyYS4yLnN1bW1hcnkkYWxpYXNlZCksIGZ1bmN0aW9uKHgpIHRvcF9zcF9nbG1zX3RhYmxlKGdsbXMubHZtLnpvc3RlcmEuMi5zdW1tYXJ5LCB4LCBwID0gMC4wNSkpIAoKIyMgZml4IHNwZWNpZXMgbmFtZXMgKHJlbW92ZSBkb3QpIAp0b3Auc3AuYWJuZC5nbG1zLmx2bS56b3N0ZXJhLjIgPC0gbGFwcGx5KHRvcC5zcC5hYm5kLmdsbXMubHZtLnpvc3RlcmEuMiwgZnVuY3Rpb24oeCkgeCAlPiUgbXV0YXRlKHNwZWNpZXMgPSBzdHJfcmVwbGFjZShzcGVjaWVzLCBwYXR0ZXJuID0gIlxcLiIsIHJlcGxhY2VtZW50ID0gIiAiKSkpCgojIyByZW5hbWUgY29sdW1ucyAoPSBncm91cCBuYW1lcykgLSByaWdodCBub3cgdGhleSBhcmUgc29tZXRoaW5nIGxpa2UgImx2bS5jbHVzdGVycy56b3N0ZXJhMiIgZXRjLgp0b3Auc3AuYWJuZC5nbG1zLmx2bS56b3N0ZXJhLjIgPC0gbGFwcGx5KHRvcC5zcC5hYm5kLmdsbXMubHZtLnpvc3RlcmEuMiwgZnVuY3Rpb24oeCkgeCAlPiUgcmVuYW1lX2F0KHZhcnMoY29udGFpbnMoImx2bS5jbHVzdGVycy56b3N0ZXJhLjIiKSksIGxpc3QofnN0cl9yZXBsYWNlX2FsbCguLCBwYXR0ZXJuID0gImx2bS5jbHVzdGVycy56b3N0ZXJhLjIiLCAiZ3JvdXBfIikpKSkKCnRvcC5zcC5hYm5kLmdsbXMubHZtLnpvc3RlcmEuMiA8LSBsYXBwbHkodG9wLnNwLmFibmQuZ2xtcy5sdm0uem9zdGVyYS4yLCBmdW5jdGlvbih4KSB4ICU+JSByZW5hbWVfYXQodmFycyhjb250YWlucygiSW50ZXJjZXB0IikpLCBsaXN0KH5zdHJfcmVwbGFjZV9hbGwoLiwgcGF0dGVybiA9ICJcXChJbnRlcmNlcHRcXCkiLCAiZ3JvdXBfMSIpKSkpCgoKIyMgcHVsbCB0aGUgYWJ1bmRhbmNlcyBmcm9tIHRoZSBvcmlnaW5hbCBjb3VudCBkZiBhbmQgYWRkIHRvIHRoZSBzdW1tYXJ5IGdsbSB0YWJsZXMgCiMjIG1ha2UgYSBsb25nIGRmIG9mIGFidW5kYW5jZXMgJiBhZGQgY2x1c3RlcnMgIAp6b28uYWJuZC56b3N0ZXJhLmxvbmcuMiA8LSB6b28uYWJuZC56b3N0ZXJhICU+JQogIHNlbGVjdCgtYyhtb250aDpyZXBsaWNhdGUpKSAlPiUKICBnYXRoZXIoa2V5ID0gInNwZWNpZXMiLCB2YWx1ZSA9ICJjb3VudCIsIC1zdGF0aW9uKSAlPiUgCiAgbXV0YXRlKGdyb3VwID0gY2FzZV93aGVuKHN0YXRpb24gPT0gIlBvZGEiIH4gMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdGlvbiA9PSAiT3RtYW5saSIgfiAyLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdGlvbiA9PSAiVnJvbW9zIiB+IDMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0aW9uID09ICJHcmFkaW5hIiB+IDQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0aW9uID09ICJSb3BvdGFtbyIgfiA1KQogICAgICAgICApCgojIyBzdW0gc3AgYWJ1bmRhbmNlcyBieSBncm91cDsgbmVzdCBieSBncm91cAp6b28uYWJuZC56b3N0ZXJhLmxvbmcuMi5zbXJ5IDwtIHpvby5hYm5kLnpvc3RlcmEubG9uZy4yICU+JSAKICBncm91cF9ieShzcGVjaWVzLCBncm91cCkgJT4lIAogIHN1bW1hcmlzZSh0b3RhbF9jb3VudCA9IHN1bShjb3VudCkpICU+JSAKICBncm91cF9ieShncm91cCkgJT4lCiAgbmVzdCgpCgojIyBhZGQgdGhlIGNvdW50cyB0byB0aGUgZ3JvdXAgZGZzIC0gd293IHRoYXQncyBhbiB1Z2x5LCB1Z2x5IGhhY2suIFdpc2ggSSBoYWQgbW9yZSB0aW1lIHRvIHdyaXRlIHRoaXMgdXAgcHJvcGVybHkuLiAKdG9wLnNwLmFibmQuZ2xtcy5sdm0uem9zdGVyYS4yIDwtIG1hcDIodG9wLnNwLmFibmQuZ2xtcy5sdm0uem9zdGVyYS4yLCB6b28uYWJuZC56b3N0ZXJhLmxvbmcuMi5zbXJ5ICU+JSBwdWxsKGdyb3VwKSwgfmxlZnRfam9pbigueCwgem9vLmFibmQuem9zdGVyYS5sb25nLjIuc21yeSAlPiUgZmlsdGVyKGdyb3VwID09IC55KSAlPiUgdW5uZXN0KCksIGJ5ID0gInNwZWNpZXMiKSkKCiMjIHNpbmNlIHRoZXNlIGFyZSBzdW0gY291bnRzIG92ZXIgYWxsIHRoZSByZXBsaWNhdGVzICh0aGF0J3Mgd2h5IHRoZSBtb25zdHJvdXMgbnVtYmVycyksIGF2ZXJhZ2UgdGhlbSB0byBiZSBtZWFuIGNvdW50cyBwZXIgZ3JvdXAuIE5CIGRpZmZlcmVudCBncm91cHMgY29uc2lzdCBvZiBkaWZmZXJlbnQgbnVtYmVycyBvZiByZXBsaWNhdGVzLCBiLmMuIHNvbWUgZ3JvdXBzIGNvbnNpc3Qgb2YgbW9yZSB0aGFuIG9uZSBzdGF0aW9uCih0b3Auc3AuYWJuZC5nbG1zLmx2bS56b3N0ZXJhLjIgPC0gbWFwMih0b3Auc3AuYWJuZC5nbG1zLmx2bS56b3N0ZXJhLjIsIGMoOCwgOCwgNCwgOCwgNCksIGZ1bmN0aW9uKHgsIHkpIHggJT4lIG11dGF0ZShtZWFuX2NvdW50ID0gdG90YWxfY291bnQveSkpCikKYGBgCgpJbiB0aGUgY2FzZSBvZiB0aGUgc2VhZ3Jhc3NlcyBhbmQgY2FzZSAyIGNsdXN0ZXJzICg9IHN0YXRpb25zKSwgdGhlIHBpY3R1cmUgaXMgc3RpbGwgbW9yZSB1bmNsZWFyLi4gSSBzdXBwb3NlIHRoaXMgaXMgaW4gbm8gc21hbGwgcGFydCBiZWNhdXNlIG9mIHRoZSBkaWZmZXJlbmNlcyAyMDEzLTE0IC0gdmVyeSBtYXJrZWQgZm9yIFBvZGEgYW5kIE90bWFubGkuIEkgc3VzcGVjdCB0aGUgc3RhdGlvbnMgY2hhbmdlZCBpbiB0aGVzZSB0d28geWVhcnMgKHdlIHdlcmUgbG9va2luZyBmb3IgWi4gbm9sdGlpIGluIDIwMTQgaW4gcGFydGljdWxhcikgLSBidXQgc3RpbGwsIHRoZXJlIGlzIG11Y2ggdmFyaWFiaWxpdHkuIEluIHRoZSBmdXR1cmUsIGl0J3MgcHJvYmFibHkgZ29pbmcgdG8gYmUgd29ydGggaXQgdG8gaGF2ZSBtb3JlIHN0YXRpb25zIGluIGEgbWVhZG93LCBpZiB3ZSByZWFsbHkgd2FudCB0byBoYXZlIGFuIGlkZWEgb2YgdGhlIGNvbW11bml0aWVzIHRoZXJlLCBhbmQgdGhlaXIgdmFyaWFiaWxpdHkuICAKVGhlIExScyBzZWVtIHRvIGJlIGEgYml0IGxvd2VyIGZvciBncm91cHMgMiwgNCwgbWF5YmUgNSB0b28gLSBzdGlsbCBub3Qgc3VyZSBpZiB5b3UgY2FuIHVzZSB0aGF0IGFzIGEgc2lnbmlmaWNhbmNlIG1lYXN1cmUuICAKRm9yIG5vdywgaW4gKipncm91cCAxKiogKD0gWjEpLCBpdCdzIGhhcmQgdG8gcGljayBzb21lIGNoYXJhY3RlcmlzdGljIHNwZWNpZXMgLSBiZWNhdXNlIG9mIHRoZSB2YXJpYWJpbGl0eSBiZXR3ZWVuIDIwMTMtMjAxNCwgbm8gZG91YnQuIFRoZSBzcGVjaWVzL3RheGEgd2l0aCBzaWduaWZpY2FudGx5ICoqaGlnaGVyIGFidW5kYW5jZSoqIGFyZTogQml0dGl1bSByZXRpY3VsYXR1bSwgQ2FwaXRlbGxhIG1pbmltYSwgUG9seWRvcmEgY2lsaWF0YSwgUHJpb25vc3ByaW8gY2lycmlmZXJhICgrIG90aGVycywgbWVkaXVtIGFidW5kYW5jZSk7IGFuZCB0aGUgb25lcyB3aXRoIGEgc2lnbmlmaWNhbnRseSAqKmxvd2VyIGFidW5kYW5jZSoqIC0gb3IgZXZlbiBhYnNlbnQgLSBDLiBnYWxsaW5hLCBBLiBvc3Ryb3Vtb3ZpLCBTLiBjbGF2YXRhLCBDLiBsaW1pY29sYSwgQy4gY29zdHVsYXRhLCBTLiBoeXN0cml4LCBTLiBncmFjaWxpcywgVC4gcHVsbHVzLiAgIApGb3IgKipncm91cCAyKiogKD0gWjIpLCB0aGUgc3BlY2llcyB3aXRoICoqaGlnaGVyIGFidW5kYW5jZSoqIC0gd2hpY2ggaXMgbm90IHJlYWxseSBhbGwgdGhhdCBoaWdoOyB0aGlzIGdyb3VwIGlzIGFsc28gbG9vc2UsIGhhcmQgdG8gZGlzdGluZ3Vpc2ggZnJvbSBncm91cCAxIC0gYXJlOiBTLiBncmFjaWxpcywgTS4gbGluZWF0dXMsIFAuIGNpbGlhdGEuIFRoZSBvbmx5IHNwZWNpZXMgd2l0aCAqKmxvd2VyIGFidW5kYW5jZSoqIC0gaW4gZmFjdCAwIC0gaXMgQWxpdHRhIHN1Y2NpbmVhLiAgCkZvciAqKmdyb3VwIDMqKiAoPSBaMyksIHRoZSBzcGVjaWVzIHdpdGggKipoaWdoZXIgYWJ1bmRhbmNlKiogYXJlOiBNLiBhY2hlcnVzaWN1bSwgUy4gZmlsaWNvcm5pcywgQS4gZGlhZGVtYS4gVGhlIHNwZWNpZXMgd2l0aCAqKmxvd2VyIGFidW5kYW5jZSoqIChvciAwKSBhcmU6IEIuIHJldGljdWxhdHVtLCBQLiBjaWxpYXRhLCBQLiBjaXJyaWZlcmEsIEEuIGFsYmEsIEEuIHN1Y2NpZW5hLCBTLiBjbGF2YXRhLCBPbGlnb2NoYWV0YSwgQS4gaW1wcm92aXN1cy4gIApGb3IgKipncm91cCA0KiogKD0gWjQpLCB0aGUgc3BlY2llcyB3aXRoICoqaGlnaGVyIGFidW5kYW5jZSoqIGFyZTogTS4gbGluZWF0dXMgKHZlcnkgbXVjaCBzbyk7IEMuIGxpbWljb2xhLCBQLiBrZWZlcnN0ZWluaSwgQy4gZ2FsbGluYSwgQy4gY2FwaXRhdGEuIFRoZSBzcGVjaWVzIHdpdGggKipsb3dlciBhYnVuZGFuY2UqKiAob3IgMCkgYXJlOiBQLiBjaWxpYXRhLCBQLiBjaXJyaWZlcmEsIEEuIHN1Y2NpbmVhLCBBLiBpbXByb3Zpc3VzLCBBLiBhbGJhLiAgCkZvciAqKmdyb3VwIDUqKiAoPSBaNSksIHRoZSBzcGVjaWVzIHdpdGggKipoaWdoZXIgYWJ1bmRhbmNlKiogYXJlOiBBLiBvc3Ryb3Vtb3ZpLCBDLiBjYXBpdGF0YSwgT2xpZ29jaGFldGEuIFRoZSBzcGVjaWVzIHdpdGggKipsb3dlciBhYnVuZGFuY2UqKiAob3IgMCkgYXJlOiBSLiBzcGxlbmRpZGEsIFQuIHB1bGx1cy4gIAoKCioqTFZNIGNsdXN0ZXJzIC0gY2FzZSAzKioKTGFzdCB0cnk6IGdyb3VwIDEgPSBaMS1aMiwgZ3JvdXAgMiA9IFozLCBncm91cCAzID0gWjQsIGdyb3VwIDQgPSBaNS4gIApDaGVjayB0aGUgbW9kZWwgYXNzdW1wdGlvbnMuICAKYGBge3IgY2hlY2tfbWVhbl92YXJpYW5jZV9sdm1fem9zdGVyYV8zfQpwbG90KG1hbnlnbG0oem9vLm12YWJuZC56b3N0ZXJhIH4gbHZtLmNsdXN0ZXJzLnpvc3RlcmEuMywgZmFtaWx5ID0gIm5lZ2F0aXZlLmJpbm9taWFsIikpCgptZWFudmFyLnBsb3Qoem9vLm12YWJuZC56b3N0ZXJhIH4gbHZtLmNsdXN0ZXJzLnpvc3RlcmEuMywgdGFibGUgPSBUUlVFKQpgYGAKCk1vcmUgb3IgbGVzcyB0aGUgc2FtZSBhcyBjYXNlIDIgYmVmb3JlIGl0LiAKCjIuIEFzc3VtZWQgcmVsYXRpb25zaGlwIGJldHdlZW4gbWVhbiBhYnVuZGFuY2UgYW5kIGVudmlyb25tZW50YWwgdmFyaWFibGVzIC0gbGluayBmdW5jdGlvbiBhbmQgZm9ybXVsYS4KCkV2ZXJ5dGhpbmcgbG9va3MgbW9yZSBvciBsZXNzIGZpbmU7IGZpdCB0aGUgbW9kZWwuIApgYGB7ciBmaXRfZ2xtc19sdm1fem9zdGVyYV8zfQpnbG1zLmx2bS56b3N0ZXJhLjMgPC0gbWFueWdsbSh6b28ubXZhYm5kLnpvc3RlcmEgfiBsdm0uY2x1c3RlcnMuem9zdGVyYS4zLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFtaWx5ID0gIm5lZ2F0aXZlLmJpbm9taWFsIikKCmBgYAoKRXhwbG9yZSB0aGUgZml0IChyZXNpZHVhbHMsIGRpYWdub3N0aWMgcGxvdHMsIGV0Yy4pLiAgCmBgYHtyIGV4cGxvcmVfZ2xtc19sdm1fem9zdGVyYV8zfQojIyByZXNpZHVhbHMgdnMgZml0dGVkIHZhbHVlcwpwbG90KGdsbXMubHZtLnpvc3RlcmEuMykKCiMjIGFsbCB0cmFkaXRpb25hbCAoZylsbSBkaWFnbm9zdGljIHBsb3RzCnBsb3QubWFueWdsbShnbG1zLmx2bS56b3N0ZXJhLjMsIHdoaWNoID0gMTozKQoKIyAjIyMgc291cmNlIG12YWJ1bmQgR0xNIHBsb3R0aW5nIGZ1bmN0aW9ucyBtb2RpZmllZCB0byB1c2UgYSBncmV5IHBhbGV0dGUgLSBJIGp1c3QgY2FuJ3QgcmVkbyB0aGVzZSBwbG90cyBvbiBteSBvd24sIHRoZSBmdW5jdGlvbiBpcyBkb2luZyB0b28gY29tcGxpY2F0ZWQgdGhpbmdzIGludGVybmFsbHkgdG8gc2NhbGUgdGhlIHggYW5kIHkgYXhlcwojIHNvdXJjZShoZXJlKGZ1bmN0aW9ucy5kaXIsICJkZWZhdWx0LnBsb3QubWFueWdsbV9ncmV5LlIiKSkKIyBzb3VyY2UoaGVyZShmdW5jdGlvbnMuZGlyLCAicGxvdC5tYW55Z2xtX2dyZXkuUiIpKQojIAojIHBhcihtZnJvdyA9IGMoMywzKSkKIyBsYXBwbHkoMzozLCBmdW5jdGlvbihpKSBwbG90Lm1hbnlnbG0uZ3JleShnbG1zLmx2bS56b3N0ZXJhLCB3aGljaCA9IGksIHN1Yi5jYXB0aW9uID0gIiIpKQojIHBhcihtZnJvdyA9IGMoMywgMykpCgpgYGAKClNhdmUgdGhlIG1vZGVsISAgCmBgYHtyIHNhdmVfZ2xtc19sdm1fem9zdGVyYV8zfQp3cml0ZV9yZHMoZ2xtcy5sdm0uem9zdGVyYS4zLCAKICAgICAgICAgIGhlcmUoc2F2ZS5kaXIsICJnbG1zX2x2bV96b3N0ZXJhXzMuUkRTIikpCmBgYAoKCkxldCdzIHNlZSB0aGUgbW9kZWwgc3VtbWFyeSAoTkIgdGFrZXMgYSBMT1Qgb2YgdGltZSBpZiB0aGVyZSBhcmUgbWFueSByZXNhbXBsaW5ncyEpLiAgCmBgYHtyIHN1bW1hcnlfZ2xtc19sdm1fem9zdGVyYV8zfQooZ2xtcy5sdm0uem9zdGVyYS4zLnN1bW1hcnkgPC0gc3VtbWFyeShnbG1zLmx2bS56b3N0ZXJhLjMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZXN0ID0gIkxSIiwgcC51bmkgPSAiYWRqdXN0ZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuQm9vdCA9IDk5OSwgIyMgbGltaXQgdGhlIG51bWJlciBvZiBwZXJtdXRhdGlvbnMgaWYgeW91IGp1c3Qgd2FudCB0byBjaGVjayBpdCBvdXQKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hvdy50aW1lID0gImFsbCIpCikKYGBgCgpUaGUgZmFjdG9yIGlzIGhpZ2hseSBzaWduaWZpY2FudCBhY2NvcmRpbmcgdG8gdGhlIG1vZGVscy4gIAogCkFnYWluLCBzYXZlIHRoZSBzdW1tYXJ5IGZvciBzYWZla2VlcGluZywgYnV0IGFsc28gcnVuIGFuIGFub3ZhLiAgCmBgYHtyIHNhdmVfc3VtbWFyeV9nbG1zX2x2bV96b3N0ZXJhXzN9CndyaXRlX3JkcyhnbG1zLmx2bS56b3N0ZXJhLjMuc3VtbWFyeSwgCiAgICAgICAgICBoZXJlKHNhdmUuZGlyLCAiZ2xtc19sdm1fem9zdGVyYV8zX3N1bW1hcnkuUkRTIikpCmBgYAoKUnVuIHRoZSBhbm92YSBvbiB0aGUgbW9kZWwuIApgYGB7ciBhbm92YV9nbG1zX2x2bV96b3N0ZXJhXzN9CihnbG1zLmx2bS56b3N0ZXJhLjMuYW92IDwtIGFub3ZhLm1hbnlnbG0oZ2xtcy5sdm0uem9zdGVyYS4zLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZXN0ID0gIkxSIiwgcC51bmkgPSAiYWRqdXN0ZWQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuQm9vdCA9IDk5OSwgIyMgbGltaXQgdGhlIG51bWJlciBvZiBwZXJtdXRhdGlvbnMgZm9yIGEgc2hvcnRlciBydW4gdGltZSAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhaXJ3aXNlLmNvbXAgPSB+bHZtLmNsdXN0ZXJzLnpvc3RlcmEuMywgIyMgY2hlY2sgdGhlIHBhaXJ3aXNlIGNvbXBhcmlzb25zIGJldHdlZW4gY2x1c3RlcnMKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaG93LnRpbWUgPSAiYWxsIikgCikKYGBgCgpBY2NvcmRpbmcgdG8gdGhlIHBhaXJ3aXNlIGNvbXBhcmlzb24sIHRoZSBjYXNlIDMgY2x1c3RlcnMgYXJlIHNpZ25pZmljYW50bHkgZGlmZmVyZW50IGZyb20gb25lIGFub3RoZXIuLiBhcHBhcmVudGx5IHN1ZmZpY2llbnRseSBzby4gIAoKU2F2ZSB0aGUgQU5PVkEsIHRvby4gIApgYGB7ciBzYXZlX2Fub3ZhX2dsbXNfbHZtX3pvc3RlcmFfM30Kd3JpdGVfcmRzKGdsbXMubHZtLnpvc3RlcmEuMy5hb3YsIAogICAgICAgICAgaGVyZShzYXZlLmRpciwgImdsbXNfbHZtX3pvc3RlcmFfM19hbm92YS5SRFMiKSkKYGBgCgpOT1cgbGV0J3MgZ2V0IHRoZSB0YXhhIHdpdGggdGhlIGhpZ2hlc3QgY29udHJpYnV0aW9ucyB0byB0aGUgdGVzdGVkIHBhdHRlcm4uICAKYGBge3IgcmVsYXRpdmVfdGF4b25fY29udHJpYl9nbG1zX2x2bV96b3N0ZXJhXzN9CiMjIGdldCB0aGUgdG9wIGNvbnRyaWJ1dGluZyBzcGVjaWVzIGZvciB0aGUgaW5pdGlhbCB6b3N0ZXJhIEdMTXMgCih0b3Auc3AuZ2xtcy5sdm0uem9zdGVyYS4zIDwtIHRvcF9uX3NwX2dsbShnbG1zLmx2bS56b3N0ZXJhLjMuYW92LCB0b3QuZGV2LmV4cGwgPSAwLjc1KQopCgojIyB1bmZvcnR1bmF0ZWx5LCBtdmFidW5kIGxpa2VzIHRvIHJlbmFtZSBteSBzcGVjaWVzIHdoZW4gY29udmVydGluZyB0aGUgZGF0YSB0byBtYXRyaXggKG5vIHNwYWNlcyBpbiBuYW1lcyksIGFuZCBzaW5jZSBJJ20gZ29pbmcgdG8gbG9vayB0aGVtIHVwIGluIG15IGluaXRpYWwgdW50cmFuc2Zvcm1lZCBjb3VudCBkYXRhLCBJIGhhdmUgdG8gY2hhbmdlIHRoZW0gYmFjay4uICAgCm5hbWVzKHRvcC5zcC5nbG1zLmx2bS56b3N0ZXJhLjMpIDwtIG5hbWVzKHRvcC5zcC5nbG1zLmx2bS56b3N0ZXJhLjMpICU+JSAKICBzdHJfcmVwbGFjZShwYXR0ZXJuID0gIlxcLiIsIHJlcGxhY2VtZW50ID0gIiAiKQoKdG9wLnNwLmdsbXMubHZtLnpvc3RlcmEuMwpgYGAKClRyeSB0byBwbG90IHRoZXNlIHRvcCBjb250cmlidXRpbmcgc3BlY2llcyAtIGZvciB3aGF0ZXZlciB0aGF0J3Mgd29ydGgsIGJlY2F1c2UgNTAgc3BlY2llcyBvbiBhIHBsb3QgaXMgc3RpbGwgYSBtb25zdHJvc2l0eS4gIAoKYGBge3IgcGxvdF9yZWxhdGl2ZV90YXhvbl9jb250cmliX2dsbXNfbHZtX3pvc3RlcmFfM30KIyMgZ2V0IHRoZSBzcGVjaWVzIGFuZCB0aGVpciBhYnVuZGFuY2VzIGZyb20gdGhlIG9yaWdpbmFsIGNvdW50IGRhdGEsIGFuZCB0cmFuc2Zvcm0gdGhlbSB0byBsb25nIGZvcm1hdAooYWJuZC50b3Auc3AuZ2xtcy5sdm0uem9zdGVyYS4zIDwtIHpvby5hYm5kLnpvc3RlcmEgJT4lIAogICBzZWxlY3Qoc3RhdGlvbiwgbmFtZXModG9wLnNwLmdsbXMubHZtLnpvc3RlcmEuMykpICU+JSAKICAgZ2F0aGVyKGtleSA9ICJzcGVjaWVzIiwgdmFsdWUgPSAiY291bnQiLCAtc3RhdGlvbikgJT4lIAogICAjIyB0dXJuIHNwZWNpZXMgaW50byBhIGZhY3Rvciwgb3IgeW91J2xsIGJlIHZlcnkgdmVyeSBzb3JyeSBsYXRlciwgd2hlbiB0aGV5J3JlIG91dCBvZiBvcmRlciBvbiB0aGUgcGxvdC4gTkIgbmVlZCB0byBiZSBpbiBSRVZFUlNFIG9yZGVyLCBiZWNhdXNlIGdncGxvdCBwbG90cyBmcm9tIGJvdHRvbSB0byB0b3AsIGFuZCBJIHdhbnQgdGhlIHRvcC1jb250cmlidXRpbmcgc3BlY2llcyBvbiB0b3AuIAogICBtdXRhdGUoc3BlY2llcyA9IGZhY3RvcihzcGVjaWVzLCBsZXZlbHMgPSByZXYobmFtZXModG9wLnNwLmdsbXMubHZtLnpvc3RlcmEuMykpKSkgJT4lIAogICBtdXRhdGUoZ3JvdXAgPSBmYWN0b3IoY2FzZV93aGVuKHN0YXRpb24gJWluJSBjKCJQb2RhIiwgIk90bWFubGkiKSB+IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdGlvbiA9PSAiVnJvbW9zIiB+IDIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXRpb24gPT0gIkdyYWRpbmEiIH4gMywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdGlvbiA9PSAiUm9wb3RhbW8iIH4gNCkpICMjIGFkZCB0aGUgZ3JvdXBzCiAgICAgICAgICApCikKCihwbG90LnRvcC5zcC5nbG1zLmx2bS56b3N0ZXJhLjMgPC0gcGxvdF90b3BfbihhYm5kLnRvcC5zcC5nbG1zLmx2bS56b3N0ZXJhLjMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBzcGVjaWVzLCB5ID0gbG9nX3lfbWluKGNvdW50KSwgY29sb3VyID0gZ3JvdXApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFicy5sZWdlbmQgPSBwYXN0ZTAoImdyb3VwIiwgYXMuY2hhcmFjdGVyKGxldmVscyhhYm5kLnRvcC5zcC5nbG1zLmx2bS56b3N0ZXJhLjMkZ3JvdXApKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWIueSA9ICJBYnVuZGFuY2UgKGxvZyh5L21pbiArIDEpKSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYWxldHRlID0gIlNldDIiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLCBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCgopCmBgYAoKCkV4dHJhY3QgdGhlIHRvcC1jb250cmlidXRpbmcgc3BlY2llcyB0byBlYWNoIGNsdXN0ZXIgKHRoaXMgc2FtZSBuaWdodG1hcmUgYWJvdmUsIGJ1dCBhcyBhIHRhYmxlKS4gVGhpcyBjaHVuayBpcyBTVElMTCBob3BlbGVzc2x5IHVnbHkgYW5kIGNsdW1zeS4gIApgYGB7ciB0YWJsZV9yZWxhdGl2ZV90YXhvbl9jb250cmliX2dsbXNfbHZtX3pvc3RlcmFfM30KdG9wLnNwLmFibmQuZ2xtcy5sdm0uem9zdGVyYS4zIDwtIGxhcHBseShuYW1lcyhnbG1zLmx2bS56b3N0ZXJhLjMuc3VtbWFyeSRhbGlhc2VkKSwgZnVuY3Rpb24oeCkgdG9wX3NwX2dsbXNfdGFibGUoZ2xtcy5sdm0uem9zdGVyYS4zLnN1bW1hcnksIHgsIHAgPSAwLjA1KSkgCgojIyBmaXggc3BlY2llcyBuYW1lcyAocmVtb3ZlIGRvdCkgCnRvcC5zcC5hYm5kLmdsbXMubHZtLnpvc3RlcmEuMyA8LSBsYXBwbHkodG9wLnNwLmFibmQuZ2xtcy5sdm0uem9zdGVyYS4zLCBmdW5jdGlvbih4KSB4ICU+JSBtdXRhdGUoc3BlY2llcyA9IHN0cl9yZXBsYWNlKHNwZWNpZXMsIHBhdHRlcm4gPSAiXFwuIiwgcmVwbGFjZW1lbnQgPSAiICIpKSkKCiMjIHJlbmFtZSBjb2x1bW5zICg9IGdyb3VwIG5hbWVzKSAtIHJpZ2h0IG5vdyB0aGV5IGFyZSBzb21ldGhpbmcgbGlrZSAibHZtLmNsdXN0ZXJzLnpvc3RlcmEzIiBldGMuCnRvcC5zcC5hYm5kLmdsbXMubHZtLnpvc3RlcmEuMyA8LSBsYXBwbHkodG9wLnNwLmFibmQuZ2xtcy5sdm0uem9zdGVyYS4zLCBmdW5jdGlvbih4KSB4ICU+JSByZW5hbWVfYXQodmFycyhjb250YWlucygibHZtLmNsdXN0ZXJzLnpvc3RlcmEuMyIpKSwgbGlzdCh+c3RyX3JlcGxhY2VfYWxsKC4sIHBhdHRlcm4gPSAibHZtLmNsdXN0ZXJzLnpvc3RlcmEuMyIsICJncm91cF8iKSkpKQoKdG9wLnNwLmFibmQuZ2xtcy5sdm0uem9zdGVyYS4zIDwtIGxhcHBseSh0b3Auc3AuYWJuZC5nbG1zLmx2bS56b3N0ZXJhLjMsIGZ1bmN0aW9uKHgpIHggJT4lIHJlbmFtZV9hdCh2YXJzKGNvbnRhaW5zKCJJbnRlcmNlcHQiKSksIGxpc3QofnN0cl9yZXBsYWNlX2FsbCguLCBwYXR0ZXJuID0gIlxcKEludGVyY2VwdFxcKSIsICJncm91cF8xIikpKSkKCgojIyBwdWxsIHRoZSBhYnVuZGFuY2VzIGZyb20gdGhlIG9yaWdpbmFsIGNvdW50IGRmIGFuZCBhZGQgdG8gdGhlIHN1bW1hcnkgZ2xtIHRhYmxlcyAKIyMgbWFrZSBhIGxvbmcgZGYgb2YgYWJ1bmRhbmNlcyAmIGFkZCBjbHVzdGVycyAgCnpvby5hYm5kLnpvc3RlcmEubG9uZy4zIDwtIHpvby5hYm5kLnpvc3RlcmEgJT4lCiAgc2VsZWN0KC1jKG1vbnRoOnJlcGxpY2F0ZSkpICU+JQogIGdhdGhlcihrZXkgPSAic3BlY2llcyIsIHZhbHVlID0gImNvdW50IiwgLXN0YXRpb24pICU+JSAKICBtdXRhdGUoZ3JvdXAgPSBjYXNlX3doZW4oc3RhdGlvbiAlaW4lIGMoIlBvZGEiLCAiT3RtYW5saSIpIH4gMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdGlvbiA9PSAiVnJvbW9zIiB+IDIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0aW9uID09ICJHcmFkaW5hIiB+IDMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0aW9uID09ICJSb3BvdGFtbyIgfiA0KQogICAgICAgICApCgojIyBzdW0gc3AgYWJ1bmRhbmNlcyBieSBncm91cDsgbmVzdCBieSBncm91cAp6b28uYWJuZC56b3N0ZXJhLmxvbmcuMy5zbXJ5IDwtIHpvby5hYm5kLnpvc3RlcmEubG9uZy4zICU+JSAKICBncm91cF9ieShzcGVjaWVzLCBncm91cCkgJT4lIAogIHN1bW1hcmlzZSh0b3RhbF9jb3VudCA9IHN1bShjb3VudCkpICU+JSAKICBncm91cF9ieShncm91cCkgJT4lCiAgbmVzdCgpCgojIyBhZGQgdGhlIGNvdW50cyB0byB0aGUgZ3JvdXAgZGZzIC0gd293IHRoYXQncyBhbiB1Z2x5LCB1Z2x5IGhhY2suIFdpc2ggSSBoYWQgbW9yZSB0aW1lIHRvIHdyaXRlIHRoaXMgdXAgcHJvcGVybHkuLiAKdG9wLnNwLmFibmQuZ2xtcy5sdm0uem9zdGVyYS4zIDwtIG1hcDIodG9wLnNwLmFibmQuZ2xtcy5sdm0uem9zdGVyYS4zLCB6b28uYWJuZC56b3N0ZXJhLmxvbmcuMy5zbXJ5ICU+JSBwdWxsKGdyb3VwKSwgfmxlZnRfam9pbigueCwgem9vLmFibmQuem9zdGVyYS5sb25nLjMuc21yeSAlPiUgZmlsdGVyKGdyb3VwID09IC55KSAlPiUgdW5uZXN0KCksIGJ5ID0gInNwZWNpZXMiKSkKCiMjIHNpbmNlIHRoZXNlIGFyZSBzdW0gY291bnRzIG92ZXIgYWxsIHRoZSByZXBsaWNhdGVzICh0aGF0J3Mgd2h5IHRoZSBtb25zdHJvdXMgbnVtYmVycyksIGF2ZXJhZ2UgdGhlbSB0byBiZSBtZWFuIGNvdW50cyBwZXIgZ3JvdXAuIE5CIGRpZmZlcmVudCBncm91cHMgY29uc2lzdCBvZiBkaWZmZXJlbnQgbnVtYmVycyBvZiByZXBsaWNhdGVzLCBiLmMuIHNvbWUgZ3JvdXBzIGNvbnNpc3Qgb2YgbW9yZSB0aGFuIG9uZSBzdGF0aW9uCih0b3Auc3AuYWJuZC5nbG1zLmx2bS56b3N0ZXJhLjMgPC0gbWFwMih0b3Auc3AuYWJuZC5nbG1zLmx2bS56b3N0ZXJhLjMsIGMoMTYsIDQsIDgsIDQpLCBmdW5jdGlvbih4LCB5KSB4ICU+JSBtdXRhdGUobWVhbl9jb3VudCA9IHRvdGFsX2NvdW50L3kpKQopCmBgYAoKSW4gdGhlIGNhc2Ugb2YgdGhlIHNlYWdyYXNzZXMgYW5kIGNhc2UgMyBjbHVzdGVycywgdGhlIHBpY3R1cmUgaXMgc3RpbGwgbW9yZSBjb25mdXNpbmcuLiAgClRoZSBMUnMgc2VlbSB0byBiZSBhIGJpdCBsb3dlciBmb3IgZ3JvdXBzIDIgYW5kIDMsIG1heWJlIDQgdG9vIC0gc3RpbGwgbm90IHN1cmUgaWYgeW91IGNhbiB1c2UgdGhhdCBhcyBhIHNpZ25pZmljYW5jZSBtZWFzdXJlLiAgCkZvciBub3csIGluICoqZ3JvdXAgMSoqICg9IFoxLVoyKSwgdGhlIHNwZWNpZXMvdGF4YSB3aXRoIHNpZ25pZmljYW50bHkgKipoaWdoZXIgYWJ1bmRhbmNlKiogYXJlOiBCaXR0aXVtIHJldGljdWxhdHVtLCBDYXBpdGVsbGEgbWluaW1hLCBPbGlnb2NoYWV0YSwgSGV0ZXJvbWFzdHVzIGZpbGlmb3JtaXMsIFBvbHlkb3JhIGNpbGlhdGEsIFByaW9ub3NwcmlvIGNpcnJpZmVyYSwgUmlzc29hIG1lbWJyYW5hY2VhLCBBYnJhIGFsYmEsIEFtcGVsaXNjYSBkaWFkZW1hICgrIG90aGVycywgbWVkaXVtIGFidW5kYW5jZSk7IGFuZCB0aGUgb25lcyB3aXRoIGEgc2lnbmlmaWNhbnRseSAqKmxvd2VyIGFidW5kYW5jZSoqIC0gb3IgZXZlbiBhYnNlbnQgLSAgUy4gY2xhdmF0YSwgIEEuIG9zdHJvdW1vdmksIEMuIGdhbGxpbmEsIFQuIHB1bGx1cy4gICAKVGhlcmUgYXJlIG1vcmUgc3BlY2llcyBzaW5nbGVkIG91dCBmb3IgdGhpcyBjbHVzdGVyLCBwcm9iYWJseSBiZWNhdXNlIG9mIHRoZSB2YXJpYWJpbGl0eSBiZXR3ZWVuIHRoZSB0d28geWVhcnMgb2Ygc2FtcGxpbmcuICAKRm9yICoqZ3JvdXAgMioqICg9IFozKSwgdGhlIHNwZWNpZXMgd2l0aCAqKmhpZ2hlciBhYnVuZGFuY2UqKiBhcmU6IE0uIGFjaGVydXNpY3VtLCBTLiBmaWxpY29ybmlzLCBBLiBkaWFkZW1hLiBUaGUgc3BlY2llcyB3aXRoICoqbG93ZXIgYWJ1bmRhbmNlKiogLSBpbiBmYWN0IDAgLSBhcmUgQi4gcmV0aWN1bGF0dW0sIFAuIGNpcnJpZmVyYSwgUy4gY2xhdmF0YSwgQS4gYWxiYSwgUC4gY2lsaWF0YSwgb2xpZ29jaGFldGVzLCBILiBmaWxpZm9ybWlzLCBSLiBzcGxlbmRpZGEuICAKRm9yICoqZ3JvdXAgMyoqICg9IFo0KSwgdGhlIHNwZWNpZXMgd2l0aCAqKmhpZ2hlciBhYnVuZGFuY2UqKiBhcmU6IE0uIGxpbmVhdHVzLCBsZXNzIHNvIC0gQy4gbGltaWNvbGEsIEwuIG9yYmljdWxhdHVzLCBQLiBrZWZlcnN0ZWluaSwgQy4gY2FwaXRhdGEsIGV0Yy4gVGhlIHNwZWNpZXMgd2l0aCAqKmxvd2VyIGFidW5kYW5jZSoqIChvciAwKSBhcmU6IFAuIGNpcnJpZmVyYSwgUC4gY2lsaWF0YSwgQS4gYWxiYSwgZXRjLiAgCkZvciAqKmdyb3VwIDQqKiAoPSBaNSksIHRoZSBzcGVjaWVzIHdpdGggKipoaWdoZXIgYWJ1bmRhbmNlKiogYXJlOiBBLiBvc3RvdW1vdmksIEMuIGNhcGl0YXRhLCBvbGlnb2NoYWV0ZXMgKHZlcnkgYWJ1bmRhbnQsIGJ1dCB3aXRoIGEgc21hbGwgTFIgLSBuaWNlISkuIFRoZSBzcGVjaWVzIHdpdGggKipsb3dlciBhYnVuZGFuY2UqKiAob3IgMCkgYXJlOiBSLiBzcGxlbmRpZGEsIFMuIGNsYXZhdGEsIEMuIGxpbWljb2xhLiAgCgoKKipBbGwgaW4gYWxsLCBJIHRoaW5rIHRoYXQgZ3JvdXAgMSAoUG9kYSArIE90bWFubGkpIGhvbGRzLCBhbmQgc28gZG9lcyBncm91cCAyIChWcm9tb3MpLiBUaGUgcXVlc3Rpb24gaXMgd2hldGhlciB0byBzZXBhcmF0ZSBHcmFkaW5hIGFuZCBSb3BvdGFtbyBpbnRvIDIgZ3JvdXBzLCBvciBpZiB0aGV5IG1ha2UgbW9yZSBzZW5zZSB0b2dldGhlci4gUm9wb3RhbW8gaXMgY2hhcmFjdGVyaXplZCBieSBhIHZlcnkgaGlnaCBudW1iZXIgb2Ygb2xpZ29jaGFldGVzLCB3aGlsZSBHcmFkaW5hJ3MgbW9zdCBkaXN0aW5ndWlzaGluZyBjaGFyYWN0ZXJpc3RpYyBpcyB0aGUgaGlnaCBudW1iZXIgb2YgTS4gbGluZWF0dXMgLSBtb3N0bHkgdmVyeSBzbWFsbCBvbmVzLCBhdHRhY2hlZCB0byB0aGUgcmhpem9tZXMsIGNsb3NlIHRvIHRoZSBzZWRpbWVudCBzdXJmYWNlIEkgcHJlc3VtZS4gQm90aCBzdGF0aW9ucyBoYXZlIEMuIGxpbWljb2xhIGluIG1lZGl1bSBhYnVuZGFuY2UsIGEgc3BlY2llcyB0aGF0IGlzIG5vdCBwcmVzZW50IGFueXdoZXJlIGVsc2UgKGlzIGl0PykuKiogCgoKVHJ5IHRvIGNvbXBhcmUgdGhlIHRocmVlIG1vZGVscy4uIApgYGB7ciBjb21wYXJlX2dsbXNfbHZtX3pvc3RlcmFfMX0KKGdsbXMubHZtLnpvc3RlcmEuY29tcCA8LSBhbm92YShnbG1zLmx2bS56b3N0ZXJhLjEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2xtcy5sdm0uem9zdGVyYS4yLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnbG1zLmx2bS56b3N0ZXJhLjMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHAudW5pID0gImFkanVzdGVkIikKKQoKYGBgCgpXZWxsIHRoaXMgaXMgdG91Z2ggdG8gaW50ZXJwcmV0Li4gTXVsdGl2YXJpYXRlIHRlc3QgdGFibGUncyBEZXYgaXMgZGVjcmVtZW50IGZyb20gdXBwZXIgbW9kZWwsIHNvIGVhY2ggcC12YWx1ZSBpbmRpY2F0ZXMgdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgbW9kZWwgYW5kIHVwcGVyIG9uZSBpcyBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50Li4uIEJ1dCBubyBpbmZvIG9uIHdoaWNoIG1vZGVsIHJlcHJlc2VudHMgdGhlIHNwZWNpZXMgbWF0cml4IGJlc3QuICAKCkknbGwgZ28gd2l0aCB0aGUgbW9kZWwgd2l0aCB0aGUgbG93ZXN0IEFJQywgc2luY2UgdGhlcmUgaXMgbm8gb3RoZXIgb2JqZWN0aXZlIGNyaXRlcmlvbiB0byBnbyB3aXRoLi4gVGhpcyBoYXBwZW5zIHRvIGJlIG1vZGVsIDIgKGdyb3VwcyA9IHN0YXRpb25zKS4gRXhhY3RseSB0aGUgc2FtZSByZXN1bHQgYXMgZnJvbSB0aGUgY2xhc3NpY2FsIG1ldGhvZHMuICAKYGBge3IgY29tcGFyZV9nbG1zX2x2bV96b3N0ZXJhXzJ9CmdsbXMubHZtLnpvc3RlcmEuMSRBSUNzdW0KZ2xtcy5sdm0uem9zdGVyYS4yJEFJQ3N1bQpnbG1zLmx2bS56b3N0ZXJhLjMkQUlDc3VtCmBgYAoKCiMjIyMjIyAqKm1hbnlHTE0gYnkgZW52aXJvbm1lbnRhbCBwYXJhbWV0ZXJzKiogIApOb3csIGxldCdzIHRyeSB0byBzZWUgYSBkaWZmZXJlbnQgdGhpbmcgLSB3aGljaCBlbnZpcm9ubWVudGFsIHBhcmFtZXRlcnMgYmVzdCBkZXNjcmliZSB0aGUgc3BlY2llcyByZXNwb25zZS4gIApJJ20gZ29pbmcgdG8gdXNlIHRoZSBQQ0EtZmlsdGVyZWQgZW52aXJvbm1lbnRhbCBkYXRhIC0gaXQncyBzdGlsbCBnb2luZyB0byBiZSBhIHNsb2csIHdpdGggNyBwb3RlbnRpYWwgcHJlZGljdG9ycy4uICAKRmlyc3QsIGNvbnN0cnVjdCB0aGUgZm9ybXVsYSBmb3IgdGhlIG1vZGVsIC0gd2lsbCBkbyBpdCBzZXBhcmF0ZWx5IGluIGNhc2UgSSBuZWVkIHRvIHVwZGF0ZSBpdCBsYXRlciwgZXRjLiAgCk5CIHRoZXJlIGlzIHllYXIgaGVyZSAtIEkgd2FudCB0byB0cnkgd2l0aCBpdCBmaXJzdCEhIEFuZCBJIGRvbid0IHdhbnQgdGhlIFNlY2NoaSBkZXB0aCAtIGl0IGhhcyBOQXMgZm9yIFZyb21vcy4gIApgYGB7ciBmb3JtdWxhX2Vudl9tYW55Z2xtX2Z1bGxfem9zdGVyYX0KKGZvcm11bGEuZW52LmdsbXMuem9zdGVyYSA8LSBmb3JtdWxhKHBhc3RlKCJ6b28ubXZhYm5kLnpvc3RlcmEgfiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZShlbnYuem9zdGVyYSAlPiUgc2VsZWN0KC1jKHN0YXRpb24sIHNlY2NoaSkpICU+JSBuYW1lcygpLCBjb2xsYXBzZSA9ICIrIikpKQopCmBgYAoKRml0IHRoZSBHTE1zIC0gaW5jbHVkaW5nIGFsbCBlbnZpcm9ubWVudGFsIHBhcmFtZXRlcnMgLSB0byB0aGUgem9zdGVyYSBhYnVuZGFuY2UgZGF0YS4gCmBgYHtyIGZpdF9nbG1zX2Vudl9mdWxsX3pvc3RlcmF9CmVudi5nbG1zLnpvc3RlcmEgPC0gbWFueWdsbShmb3JtdWxhLmVudi5nbG1zLnpvc3RlcmEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gZW52Lnpvc3RlcmEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYW1pbHkgPSAibmVnYXRpdmUuYmlub21pYWwiKQoKYGBgCgpFeHBsb3JlIHRoZSBmaXQgKHJlc2lkdWFscywgZGlhZ25vc3RpYyBwbG90cywgZXRjLikuICAKYGBge3IgZXhwbG9yZV9nbG1zX2Vudl9mdWxsX3pvc3RlcmF9CiMjIHJlc2lkdWFscyB2cyBmaXR0ZWQgdmFsdWVzCnBsb3QoZW52LmdsbXMuem9zdGVyYSkKCgojIyBhbGwgdHJhZGl0aW9uYWwgKGcpbG0gZGlhZ25vc3RpYyBwbG90cwpwbG90Lm1hbnlnbG0oZW52LmdsbXMuem9zdGVyYSwgd2hpY2ggPSAxOjMpCgoKIyAjIyMgc291cmNlIG12YWJ1bmQgR0xNIHBsb3R0aW5nIGZ1bmN0aW9ucyBtb2RpZmllZCB0byB1c2UgYSBncmV5IHBhbGV0dGUgLSBJIGp1c3QgY2FuJ3QgcmVkbyB0aGVzZSBwbG90cyBvbiBteSBvd24sIHRoZSBmdW5jdGlvbiBpcyBkb2luZyB0b28gY29tcGxpY2F0ZWQgdGhpbmdzIGludGVybmFsbHkgdG8gc2NhbGUgdGhlIHggYW5kIHkgYXhlcwojIHNvdXJjZShoZXJlKGZ1bmN0aW9ucy5kaXIsICJkZWZhdWx0LnBsb3QubWFueWdsbV9ncmV5LlIiKSkKIyBzb3VyY2UoaGVyZShmdW5jdGlvbnMuZGlyLCAicGxvdC5tYW55Z2xtX2dyZXkuUiIpKQojIAojIHBhcihtZnJvdyA9IGMoMiwyKSkKIyBsYXBwbHkoMTozLCBmdW5jdGlvbihpKSBwbG90Lm1hbnlnbG0uZ3JleShnbG1zLmx2bS56b3N0ZXJhLCB3aGljaCA9IGksIHN1Yi5jYXB0aW9uID0gIiIpKQojIHBhcihtZnJvdyA9IGMoMSwgMSkpCgpgYGAKCldlbGwsIGl0J3MgZ29vZCBlbm91Z2ggaWYgeW91IGFzayBtZSAoc3RpbGwgdGhlIGtpbmRhIHN0cmFuZ2UgImxpbmUiIGF0IGxpbi5wcmVkID0gLTY7IG90aGVyd2lzZSByZXNpZHVhbHMgYXJlIHJhbmRvbSBlbm91Z2gpLiAgCgpTYXZlIHRoZSBtb2RlbCEgIApgYGB7ciBzYXZlX2dsbXNfZW52X2Z1bGxfem9zdGVyYX0Kd3JpdGVfcmRzKGVudi5nbG1zLnpvc3RlcmEsIAogICAgICAgICAgaGVyZShzYXZlLmRpciwgImdsbXNfZW52X3pvc3RlcmEuUkRTIikpCmBgYAoKQmVmb3JlIGdvaW5nIG9mZiBhbmQgcnVubmluZyBhbiBBTk9WQSB0byBjaGVjayB3aGljaCBwcmVkaWN0b3JzIGJlc3QgZXhwbGFpbiB0aGUgc3BlY2llcyBhYnVuZGFuY2UgcGF0dGVybnMsIEknbGwgdHJ5IHRvIHJlZHVjZSB0aGUgbW9kZWwgYSBsaXR0bGUgLSBpdCBtaWdodCBldmVuIGltcHJvdmUgdGhlIGZpdCwgbm90IHRvIG1lbnRpb24gdGhlIHJ1biB0aW1lLiAgCmBgYHtyIHNlbGVjdF90b3BfZ2xtX2Vudl96b3N0ZXJhfQojIyBzZWxlY3Rpb24gZnVuY3Rpb24gZGVmaW5lZCBpbiB0aGUgc2FuZCBzZWN0aW9uIAp0b3AuZW52LmdsbS5yZWQuem9zdGVyYSA8LSBldmFsdWF0ZV9nbG1zX2VudihlbnYuZ2xtcy56b3N0ZXJhKQoKYGBgCgpDaGVjayBpdHMgZml0LiAKYGBge3IgZXhwbG9yZV90b3BfZ2xtX2Vudl9yZWRfem9zdGVyYX0KIyMgcmVzaWR1YWxzIHZzIGZpdHRlZCB2YWx1ZXMKcGxvdCh0b3AuZW52LmdsbS5yZWQuem9zdGVyYSkKCgojIyBhbGwgdHJhZGl0aW9uYWwgKGcpbG0gZGlhZ25vc3RpYyBwbG90cwpwbG90Lm1hbnlnbG0odG9wLmVudi5nbG0ucmVkLnpvc3RlcmEsIHdoaWNoID0gMTozKQpgYGAKCkkgdGhpbmsgaXQncyBmaW5lOyBtaWdodCBldmVuIGJlIGJldHRlciB0aGFuIHRoZSBmdWxsIG1vZGVsLi4gClNhdmUgaXQsIHRvby4gCmBgYHtyIHNhdmVfdG9wX2dsbV9lbnZfcmVkX3pvc3RlcmF9CndyaXRlX3Jkcyh0b3AuZW52LmdsbS5yZWQuem9zdGVyYSwgCiAgICAgICAgICBoZXJlKHNhdmUuZGlyLCAiZ2xtc190b3BfZW52X3JlZF96b3N0ZXJhLlJEUyIpKQpgYGAKCgpSdW4gQU5PVkEgb24gdGhpcyBtb2RlbC4KYGBge3IgYW5vdmFfdG9wX2dsbV9lbnZfcmVkX3pvc3RlcmF9Cih0b3AuZW52LmdsbS5yZWQuem9zdGVyYS5hb3YgPC0gYW5vdmEubWFueWdsbSh0b3AuZW52LmdsbS5yZWQuem9zdGVyYSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRlc3QgPSAiTFIiLCBwLnVuaSA9ICJhZGp1c3RlZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbkJvb3QgPSA5OTksICMjIGxpbWl0IHRoZSBudW1iZXIgb2YgcGVybXV0YXRpb25zIGZvciBhIHNob3J0ZXIgcnVuIHRpbWUgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNob3cudGltZSA9ICJhbGwiKSAKKQpgYGAKCk5pY2UsIGFsbCB0ZXJtcyBhcmUgc2lnbmlmaWNhbnQgbm93ISAKQWdhaW4sIGFzIHdpdGggdGhlIHNhbmQgc2FtcGxlcywgdGhlcmUgaXMgb25lIGV1dHJvcGhpY2F0aW9uIHRlcm0gKyBvbmUgc2VkaW1lbnQgY29tcG9zaXRpb24gKyBzZWFncmFzcyBwYXJhbWV0ZXJzLiBTZWVtcyByZWFzb25hYmxlIGVub3VnaC4gIAoKU2F2ZSB0aGlzIEFOT1ZBICh0YWtlcyB0b28gbG9uZyB0byBydW4gYW5ldykuICAKYGBge3Igc2F2ZV9hbm92YV90b3BfZ2xtX2Vudl9yZWRfem9zdGVyYX0Kd3JpdGVfcmRzKHRvcC5lbnYuZ2xtLnJlZC56b3N0ZXJhLmFvdiwgCiAgICAgICAgICBoZXJlKHNhdmUuZGlyLCAiZ2xtc190b3BfZW52X3JlZF96b3N0ZXJhX2Fub3ZhLlJEUyIpKQpgYGAKCgpHZXQgdGhlIHRheGEgd2l0aCB0aGUgaGlnaGVzdCBjb250cmlidXRpb25zIHRvIHRoZSB0ZXN0ZWQgcGF0dGVybiAoaGVyZSAtIHNwZWNpZXMgbW9zdCBhZmZlY3RlZCBieSBjaGFuZ2VzIGluIHdhdGVyL2Vudmlyb25tZW50YWwgcXVhbGl0eSBwYXJhbWV0ZXJzKS4gIApgYGB7ciByZWxhdGl2ZV90YXhvbl9jb250cmliX3RvcF9nbG1fZW52X3JlZF96b3N0ZXJhfQojIyBnZXQgdGhlIHRvcCBjb250cmlidXRpbmcgc3BlY2llcyBmb3IgdGhlIGVudmlyb25tZW50YWwgcGFyYW1ldGVyIHpvc3RlcmEgR0xNcyAKKHRvcC5zcC5nbG1zLmVudi5yZWQuem9zdGVyYSA8LSB0b3Bfbl9zcF9nbG0odG9wLmVudi5nbG0ucmVkLnpvc3RlcmEuYW92LCB0b3QuZGV2LmV4cGwgPSAwLjc1KQopCgojIyB1bmZvcnR1bmF0ZWx5LCBtdmFidW5kIGxpa2VzIHRvIHJlbmFtZSBteSBzcGVjaWVzIHdoZW4gY29udmVydGluZyB0aGUgZGF0YSB0byBtYXRyaXggKG5vIHNwYWNlcyBpbiBuYW1lcyksIGFuZCBzaW5jZSBJJ20gZ29pbmcgdG8gbG9vayB0aGVtIHVwIGluIG15IGluaXRpYWwgdW50cmFuc2Zvcm1lZCBjb3VudCBkYXRhLCBJIGhhdmUgdG8gY2hhbmdlIHRoZW0gYmFjay4uICAgRE9OJ1QgQkUgSU4gQSBIVVJSWSBUTyBETyBUSEFUIElGIFlPVSBXQU5UIFRPIFNVQlNFVCBUSEUgT1JJR0lOQUwgTUFUUklYIEJFRk9SRSBSVU5OSU5HIFRSQUlUR0xNIApuYW1lcyh0b3Auc3AuZ2xtcy5lbnYucmVkLnpvc3RlcmEpIDwtIG5hbWVzKHRvcC5zcC5nbG1zLmVudi5yZWQuem9zdGVyYSkgJT4lIAogIHN0cl9yZXBsYWNlKHBhdHRlcm4gPSAiXFwuIiwgcmVwbGFjZW1lbnQgPSAiICIpCgpgYGAKCkknbSBnb2luZyB0byBwbG90IHRoZXNlIHRvcCBjb250cmlidXRpbmcgc3BlY2llcywgYnV0IEknbSBub3QgdXNpbmcgdGhlIHBsb3QuIEF0IGxlYXN0IHRoaXMgdGltZSBpdCdzIG1vcmUgbWFuYWdlYWJsZSwgYnV0IHN0aWxsIG5vdCBwcmVzZW50YWJsZSBlbm91Z2guLiAKCmBgYHtyIHBsb3RfcmVsYXRpdmVfdGF4b25fY29udHJpYl90b3BfZ2xtX2Vudl9yZWRfem9zdGVyYX0KIyMgZ2V0IHRoZSBzcGVjaWVzIGFuZCB0aGVpciBhYnVuZGFuY2VzIGZyb20gdGhlIG9yaWdpbmFsIGNvdW50IGRhdGEsIGFuZCB0cmFuc2Zvcm0gdGhlbSB0byBsb25nIGZvcm1hdAooYWJuZC50b3Auc3AuZ2xtcy5lbnYucmVkLnpvc3RlcmEgPC0gem9vLmFibmQuem9zdGVyYSAlPiUgCiAgIHNlbGVjdChzdGF0aW9uLCBuYW1lcyh0b3Auc3AuZ2xtcy5lbnYucmVkLnpvc3RlcmEpKSAlPiUgCiAgIGdhdGhlcihrZXkgPSAic3BlY2llcyIsIHZhbHVlID0gImNvdW50IiwgLXN0YXRpb24pICU+JSAKICAgIyMgdHVybiBzcGVjaWVzIGludG8gYSBmYWN0b3IsIG9yIHlvdSdsbCBiZSB2ZXJ5IHZlcnkgc29ycnkgbGF0ZXIsIHdoZW4gdGhleSdyZSBvdXQgb2Ygb3JkZXIgb24gdGhlIHBsb3QuIE5CIG5lZWQgdG8gYmUgaW4gUkVWRVJTRSBvcmRlciwgYmVjYXVzZSBnZ3Bsb3QgcGxvdHMgZnJvbSBib3R0b20gdG8gdG9wLCBhbmQgSSB3YW50IHRoZSB0b3AtY29udHJpYnV0aW5nIHNwZWNpZXMgb24gdG9wLiAKICAgbXV0YXRlKHNwZWNpZXMgPSBmYWN0b3Ioc3BlY2llcywgbGV2ZWxzID0gcmV2KG5hbWVzKHRvcC5zcC5nbG1zLmVudi5yZWQuem9zdGVyYSkpKSkgJT4lIAogICAjIyBhZGQgY2x1c3RlcnMgZnJvbSBMVk0gYXMgYSBjb2x1bW4KICAgbXV0YXRlKGdyb3VwID0gY2FzZV93aGVuKHN0YXRpb24gPT0gIlBvZGEiIH4gMSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0aW9uID09ICJPdG1hbmxpIiB+IDIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdGlvbiA9PSAiVnJvbW9zIiB+IDMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdGlvbiA9PSAiR3JhZGluYSIgfiA0LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXRpb24gPT0gIlJvcG90YW1vIiB+IDUpKQopCgoKKHBsb3QudG9wLnNwLmdsbXMuZW52LnJlZC56b3N0ZXJhIDwtIHBsb3RfdG9wX24oYWJuZC50b3Auc3AuZ2xtcy5lbnYucmVkLnpvc3RlcmEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0gc3BlY2llcywgeSA9IGxvZ195X21pbihjb3VudCksIGNvbG91ciA9IGZhY3Rvcihncm91cCkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYnMubGVnZW5kID0gdW5pcXVlKGFibmQudG9wLnNwLmdsbXMuZW52LnJlZC56b3N0ZXJhJGdyb3VwKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWIueSA9ICJBYnVuZGFuY2UgKGxvZyh5L21pbiArIDEpKSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFsZXR0ZSA9ICJTZXQyIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSArIAogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCgopCmBgYAoKCkV4dHJhY3QgdGhlIHRheG9uIGluZm9ybWF0aW9uICh1bml2YXJpYXRlIHRlc3RzKSBmcm9tIHRoZSBtb2RlbCBBTk9WQSB0byBwcmVzZW50IGFzIGEgdGFibGUgKHByb2JhYmx5IGJldHRlciB0aGFuIHRoaXMgcGxvdCwgYWx0aG91Z2ggaXQncyBpbmZvcm1hdGl2ZSkuICAKYGBge3IgdGFibGVfcmVsYXRpdmVfdGF4b25fY29udHJpYl90b3BfZ2xtX2Vudl9yZWRfem9zdGVyYX0KIyMgZXh0cmFjdCB0aGUgdW5pdmFyaWF0ZSB0ZXN0IGNvZWZmaWNpZW50cyAoTFIpIGZyb20gdGhlIGVudmlyb25tZW50YWwgbW9kZWwgQU5PVkEuIE5CIGtlZXAgdGhlIHJvdyBuYW1lcyB3aGVuIGNvbnZlcnRpbmcgdGhlIG1hdHJpeCB0byB0aWJibGUhIAp0YWJsZS50b3Auc3AuZ2xtcy5lbnYucmVkLnpvc3RlcmEgPC0gYXNfdGliYmxlKHRvcC5lbnYuZ2xtLnJlZC56b3N0ZXJhLmFvdiR1bmkudGVzdCwgcm93bmFtZXMgPSAidmFyIikKCiMjIGZpeCB0aGUgc3BlY2llcyBuYW1lcyAtIHJlbW92ZSBmaXJzdCBkb3IgIApuYW1lcyh0YWJsZS50b3Auc3AuZ2xtcy5lbnYucmVkLnpvc3RlcmEpIDwtIG5hbWVzKHRhYmxlLnRvcC5zcC5nbG1zLmVudi5yZWQuem9zdGVyYSkgJT4lIAogIHN0cl9yZXBsYWNlKHBhdHRlcm4gPSAiXFwuIiwgcmVwbGFjZW1lbnQgPSAiICIpCgojIyBzdWJzZXQgb25seSB0aGUgdG9wIHNwZWNpZXMgKGV4cGxhaW5pbmcgfjc1JSBvZiB0aGUgZGF0YXNldCB2YXJpYXRpb24pCnRhYmxlLnRvcC5zcC5nbG1zLmVudi5yZWQuem9zdGVyYSA8LSB0YWJsZS50b3Auc3AuZ2xtcy5lbnYucmVkLnpvc3RlcmEgJT4lIAogIHNlbGVjdCh2YXIsIG5hbWVzKHRvcC5zcC5nbG1zLmVudi5yZWQuem9zdGVyYSkpCgojIyB0cmFuc3Bvc2UsIGJlY2F1c2UgYSB0YWJsZSB3aXRoIDUwIGNvbHVtbnMgaXMganVzdCB1bnJlYWRhYmxlCih0YWJsZS50b3Auc3AuZ2xtcy5lbnYucmVkLnpvc3RlcmEgPC0gdGFibGUudG9wLnNwLmdsbXMuZW52LnJlZC56b3N0ZXJhICU+JQogICAgZ2F0aGVyKGtleSA9IHNwZWNpZXMsIHZhbHVlID0gdmFsdWUsIC12YXIpICU+JSAKICAgIHNwcmVhZChrZXkgPSB2YXIsIHZhbHVlID0gdmFsdWUpICU+JSAKICAgICMjIGFycmFuZ2UgYXMgYmVmb3JlICh0ZXJtcyBpbiB0aGUgb3JkZXIgdGhleSBhcHBlYXIgaW4gdGhlIG1vZGVsLCBhbmQgYnkgZGVzY2VuZGluZyB2YWx1ZSBvZiB0aGUgTFIgZm9yIHRoZSBmaXJzdCBtb2RlbCB0ZXJtIC0gaGVyZSwgTnRvdGFsKS4gQWxzbyBnZXQgcmlkIG9mIHRoZSBpbnRlcmNlcHQgKGl0J3MgYWxsLU5BIGFueXdheSkuCiAgICBzZWxlY3Qoc3BlY2llcywgTnRvdGFsLCBzYW5kLCBzaG9vdF9jb3VudCwgYWdfYmlvbWFzc193ZXQsIGJnX2Jpb21hc3Nfd2V0KSAlPiUKICAgIGFycmFuZ2UoZGVzYyhOdG90YWwpKSAKKQpgYGAKClNhdmUgdGhpcyB0byBhIGZpbGUgLSB3aWxsIGhhdmUgdG8gZm9ybWF0IGl0IGFzIGEgbmljZSB0YWJsZSBieSBoYW5kLCB1bmZvcnR1bmF0ZWx5LiAKYGBge3Igc2F2ZV90YWJsZV9yZWxhdGl2ZV90YXhvbl9jb250cmliX3RvcF9nbG1fZW52X3JlZF96b3N0ZXJhfQp3cml0ZV9jc3YodGFibGUudG9wLnNwLmdsbXMuZW52LnJlZC56b3N0ZXJhLCAKICAgICAgICAgIGhlcmUoc2F2ZS5kaXIsICJ0YXhhX2NvbnRyaWJfZ2xtc190b3BfZW52X3JlZF96b3N0ZXJhLmNzdiIpKQpgYGAKCgpDYWxjdWxhdGUgdGhlIHBlcmNlbnRhZ2UgY29udHJpYnV0aW9uIG9mIGVhY2ggb2YgdGhlc2Ugc3BlY2llcyB0byBlYWNoIG9mIHRoZSBtb2RlbCB0ZXJtcyAoRGV2KHRlcm0pID0gU3VtLW9mLUxSIC0gc3VtIG9mIHRoZSBMUnMgZm9yIHRoZSBpbmRpdmlkdWFsIHVuaXZhcmlhdGUgc3BlY2llcyB0ZXN0cykuLiAKYGBge3IgdGFibGVfcHJvcF9yZWxhdGl2ZV90YXhvbl9jb250cmliX3RvcF9nbG1fZW52X3JlZF96b3N0ZXJhfQojIyBnZXQgdGhlIHRvdGFsIGRldmlhbmNlIChTdW0tb2YtTFIpIGZvciBlYWNoIG1vZGVsIHRlcm0KKGRldi50ZXJtcy50b3AuZ2xtcy5lbnYuem9zdGVyYSA8LSBhc190aWJibGUodG9wLmVudi5nbG0ucmVkLnpvc3RlcmEuYW92JHRhYmxlLCByb3duYW1lcyA9ICJ2YXIiKSAlPiUKICAgIyMgZ2V0IHJpZCBvZiB1bm5lY2Vzc2FyeSB2YXJpYWJsZXMgKEkgb25seSB3YW50IHRoZSBkZXZpYW5jZSB2YWx1ZSBmb3IgZWFjaCB0ZXJtKSBhbmQgaW50ZXJjZXB0IHRlcm0gCiAgIHNlbGVjdCh2YXIsIERldikgJT4lIAogICBmaWx0ZXIodmFyICE9ICIoSW50ZXJjZXB0KSIpICU+JSAKICAgIyMgdHJhbnNwb3NlIAogICBnYXRoZXIodmFyaWFibGUsIHZhbHVlLCAtdmFyKSAlPiUKICAgc3ByZWFkKHZhciwgdmFsdWUpICU+JSAKICAgIyMgZ2V0IHJpZCBvZiBmaXJzdCBjb2x1bW4gYW5kIHJlYXJyYW5nZSBjb2x1bW5zIHRvIG1hdGNoIHRhYmxlIG9mIGRldmlhbmNlcyBvZiB1bml2YXJpYXRlIHRlc3RzIGZvciBzcGVjaWVzIAogICBzZWxlY3QoLXZhcmlhYmxlKSAlPiUgCiAgIHNlbGVjdChOdG90YWwsIHNhbmQsIHNob290X2NvdW50LCBhZ19iaW9tYXNzX3dldCwgYmdfYmlvbWFzc193ZXQpCikgIAoKIyMgY2FsY3VsYXRlIHRoZSBwcm9wb3J0aW9uIGNvbnRyaWJ1dGlvbiBvZiBlYWNoIHNwZWNpZXMgdG8gZWFjaCBwYXJhbWV0ZXIgZGV2aWFuY2UKcHJvcC50b3Auc3AuZ2xtcy5lbnYucmVkLnpvc3RlcmEgPC0gbWFwMl9kZih0YWJsZS50b3Auc3AuZ2xtcy5lbnYucmVkLnpvc3RlcmEgJT4lIHNlbGVjdCgtc3BlY2llcyksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRldi50ZXJtcy50b3AuZ2xtcy5lbnYuem9zdGVyYSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB+LngvLnkpCgojIyBhZGQgYmFjayB0aGUgc3BlY2llcyAKKHByb3AudG9wLnNwLmdsbXMuZW52LnJlZC56b3N0ZXJhIDwtIGJpbmRfY29scyh0YWJsZS50b3Auc3AuZ2xtcy5lbnYucmVkLnpvc3RlcmEgJT4lIHNlbGVjdChzcGVjaWVzKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvcC50b3Auc3AuZ2xtcy5lbnYucmVkLnpvc3RlcmEpCikKYGBgCgoKCgpJJ2xsIGRvIHRoZSBwc2V1ZG8tdHJhaXRzIGFuYWx5c2lzIC0gZml0IHNpbmdsZSBwcmVkaWN0aXZlIG1vZGVsIGZvciBhbGwgc3BlY2llcyBhdCBhbGwgc2l0ZXMsIGJ1dCB3L28gYXR0ZW1wdGluZyB0byBleHBsYWluIHRoZSBkaWZmZXJlbnQgcmVzcG9uc2VzIHVzaW5nIHRyYWl0cyAtIHRoZSBzcGVjaWVzIElEIGlzIHVzZWQgaW4gcGxhY2Ugb2YgYSB0cmFpdHMgbWF0cml4KSwgYWx0aG91Z2ggSSBkb24ndCB0aGluayBpdCB3aWxsIGFtb3VudCB0byBhbnl0aGluZyB1c2VmdWwuICAgCk5CIG9ubHkgdXNlIHRoZSB0b3Agc3BlY2llcyB0aGF0IGV4aGliaXRlZCBhIHJlYWN0aW9uIGluIHRoZSBlbnZpcm9ubWVudGFsIG1vZGVsIGZpdCAoPSB0aGUgb25lcyBhY2NvdW50aW5nIGZvciB+NzUlIG9mIHRoZSB0b3RhbCB2YXJpYWJpbGl0eSksIGFuZCBvbmx5IHRoZSBzaWduaWZpY2FudCBwcmVkaWN0b3JzIC0gdG8gaW1wcm92ZSBydW4gdGltZXMuICAgCmBgYHtyIHNwX3Jlc3BvbnNlX3RvcF9nbG1fZW52X3JlZF96b3N0ZXJhfQpzcC5yZXNwb25zZS5nbG1zLmVudi5yZWQuem9zdGVyYSA8LSB0cmFpdGdsbShMID0gbXZhYnVuZCh6b28uYWJuZC5mbHQuem9zdGVyYVssIG5hbWVzKHRvcC5zcC5nbG1zLmVudi5yZWQuem9zdGVyYSldKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFIgPSBhcy5tYXRyaXgoZW52Lnpvc3RlcmEgJT4lIHNlbGVjdChOdG90YWwsIHNhbmQsIHNob290X2NvdW50LCBhZ19iaW9tYXNzX3dldCwgYmdfYmlvbWFzc193ZXQpKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJtYW55Z2xtIikKCgpzcC5yZXNwb25zZS5nbG1zLmVudi5yZWQuem9zdGVyYSRmb3VydGguY29ybmVyCgoKIyBwbG90IHRoaXMgCmEueiA8LSBtYXgoYWJzKHNwLnJlc3BvbnNlLmdsbXMuZW52LnJlZC56b3N0ZXJhJGZvdXJ0aC5jb3JuZXIpKQpjb2xvcnQgPC0gY29sb3JSYW1wUGFsZXR0ZShjKCJibHVlIiwid2hpdGUiLCJyZWQiKSkgCnBsb3Quc3BwLnogPC0gbGF0dGljZTo6bGV2ZWxwbG90KHQoYXMubWF0cml4KHNwLnJlc3BvbnNlLmdsbXMuZW52LnJlZC56b3N0ZXJhJGZvdXJ0aC5jb3JuZXIpKSwgeGxhYiA9ICJFbnZpcm9ubWVudGFsIFZhcmlhYmxlcyIsCiAgICAgICAgICAgICAgICAgICAgIHlsYWIgPSAiU3BlY2llcyIsIGNvbC5yZWdpb25zID0gY29sb3J0KDEwMCksIGF0ID0gc2VxKC1hLnosIGEueiwgbGVuZ3RoID0gMTAwKSwKICAgICAgICAgICAgICAgICAgICAgc2NhbGVzID0gbGlzdCh4ID0gbGlzdChyb3QgPSA0NSkpKQpwcmludChwbG90LnNwcC56KQpgYGAKCkhlcmUgYXQgbGVhc3QgdGhlIGRpcmVjdGlvbnMgYXJlIGEgbGl0dGxlIG1vcmUgY29oZXJlbnQgdGhhbiB0aGUgZW52aXJvbm1lbnRhbCBwYXJhbWV0ZXJzIGZvciB0aGUgc2FuZCBzdGF0aW9ucyAoc2VhZ3Jhc3MgYmlvbWFzc2VzIG1vcmUgb3IgbGVzcyBpbiB0aGUgc2FtZSBkaXJlY3Rpb24sIGV0Yy4pLiBUaGUgYmVsb3ctZ3JvdW5kIGJpb21hc3MgZXhlcnRzIG1vcmUgcHJvbm91bmNlZCBpbmZsdWVuY2Ugb24gdGhlIHNwZWNpZmljIGFidW5kYW5jZXMgLSBub3JtYWwsIHNpbmNlIG1vc3Qgb2YgdGhlc2UgYXJlIGluZmF1bmEuICAKCg==